From e59da27e83499680c6533b61e4c895f84353a248 Mon Sep 17 00:00:00 2001 From: Fin Orr Date: Sat, 17 Feb 2024 18:45:34 +0700 Subject: [PATCH 1/4] New repo format, still missing unit tests, CMakeLists WIP --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f65e50a..4a8034b 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ## Use Case Scenarios -Sound a bit asbtract? No worries, here's some examples of where PolyFit might help solve your problem. +Sound a bit asbtract? No worries, here's some examples of where PolyFit might solve a problem you have. **Curve Fitting in Data Analysis** - In climate science research, polynomial curve fitting is applied to analyse historical temperature data and predict future climate trends, aiding in understanding global warming patterns. @@ -33,18 +33,19 @@ Sound a bit asbtract? No worries, here's some examples of where PolyFit might he - map building and refinement; and - sensor calibration. -**Function Approximation in Optimization** +**Function Approximation in Optimisation** - Civil engineers use polynomial approximations to model stress-strain relationships in structural materials for bridge design. By approximating complex material behavior with polynomials, engineers can optimise structural designs for safety and durability under various loading conditions. **Transform Functions and Control Systems** -- This was the original purpose of the library; to generate transfer functions for systems. Woo! - Polynomial models are vital in representing system transfer functions, which describe the relationship between inputs and outputs of a dynamic system. By mapping polynomials to transfer functions, engineers can model the behavior of diverse systems across various domains, including aerospace, automotive, and industrial control. -- For instance, in control systems engineering, polynomials are transformed into transfer functions to characterise the dynamics of physical systems, such as aircraft, vehicles, and manufacturing processes! These transfer functions capture the system's response to inputs and enable engineers to design control algorithms to achieve desired performance objectives, such as stability, responsiveness, and robustness. +- For instance, in control systems engineering, polynomials are transformed into transfer functions to characterise the dynamics of physical systems, such as aircraft, vehicles, and manufacturing processes! +- These transfer functions capture the system's response to inputs and enable engineers to design control algorithms to achieve desired performance objectives, such as stability, responsiveness, and robustness. - With transfer functions derived from polynomials, engineers can perform advanced control systems analysis techniques, such as Root-Locus, frequency response analysis, and pole-zero analysis. **Control System Applications** -- In industrial automation, polynomial controllers are used to regulate robotic arm movements in manufacturing processes. For example, in automotive assembly lines, polynomial-based controllers ensure accurate positioning of robotic arms for welding and assembly tasks. - +- In industrial automation, polynomial controllers regulate motors by translating input commands into precise motor outputs. +- By applying specific inputs and measuring corresponding outputs, such as speed or torque, engineers optimise manufacturing processes. +- For example, in controlling fluid pump outputs, polynomial controllers enable adjustments to achieve desired pressure levels or flow rates, enhancing efficiency and product quality. ## Features From 25140855e4be4ddae23e14f7ee5614c3a6813e22 Mon Sep 17 00:00:00 2001 From: Fin Orr Date: Sat, 17 Feb 2024 18:46:08 +0700 Subject: [PATCH 2/4] New repo structure, still missing unit tests, cmakelists are incorrect --- .clang-format | 289 +++++++++++ .clang-tidy | 90 ++++ .gitattributes | 12 + .github/ISSUE_TEMPLATE.md | 32 ++ .github/ISSUE_TEMPLATE/FEATURE.md | 27 ++ .github/ISSUE_TEMPLATE/ISSUE.md | 48 ++ .github/ISSUE_TEMPLATE/QUESTION.md | 15 + .github/ISSUE_TEMPLATE/config.yml | 1 + .github/PULL_REQUEST_TEMPLATE.md | 21 + .github/PULL_REQUEST_TEMPLATE/ccc.md | 49 ++ .../pull_request_template.md | 42 ++ .gitignore | 67 ++- .gitmodules | 3 + BuildOptions.cmake | 121 +++++ CMakeLists.txt | 110 ++++- LICENSE | 222 ++++++++- Makefile | 203 ++++++++ Packaging.cmake | 30 ++ README.md | 235 +++++++-- demo.c | 53 --- docs/CODE_OF_CONDUCT.md | 5 + CONTRIBUTING.md => docs/CONTRIBUTING.md | 2 +- src/CMakeLists.txt | 3 + src/app/CMakeLists.txt | 10 + src/app/demo.c | 90 ++++ src/lib/CMakeLists.txt | 26 + src/lib/polyfit/CMakeLists.txt | 2 + polyFit.c => src/lib/polyfit/polyfit.c | 4 +- polyFit.h => src/lib/polyfit/polyfit.h | 2 +- src/utility/CMakeLists.txt | 15 + test/CMakeLists.txt | 32 ++ test/README.md | 1 + tools/CI.jenkinsfile | 427 +++++++++++++++++ tools/Jenkinsfile | 449 ++++++++++++++++++ tools/deploy_skeleton.sh | 170 +++++++ tools/download_and_deploy.sh | 10 + tools/install_arm_gcc.sh | 43 ++ tools/install_deps.sh | 126 +++++ tools/setup_env.sh | 62 +++ 39 files changed, 2985 insertions(+), 164 deletions(-) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .gitattributes create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/FEATURE.md create mode 100644 .github/ISSUE_TEMPLATE/ISSUE.md create mode 100644 .github/ISSUE_TEMPLATE/QUESTION.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/ccc.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md create mode 100644 .gitmodules create mode 100644 BuildOptions.cmake create mode 100644 Makefile create mode 100644 Packaging.cmake delete mode 100644 demo.c create mode 100644 docs/CODE_OF_CONDUCT.md rename CONTRIBUTING.md => docs/CONTRIBUTING.md (95%) create mode 100644 src/CMakeLists.txt create mode 100644 src/app/CMakeLists.txt create mode 100644 src/app/demo.c create mode 100644 src/lib/CMakeLists.txt create mode 100644 src/lib/polyfit/CMakeLists.txt rename polyFit.c => src/lib/polyfit/polyfit.c (99%) rename polyFit.h => src/lib/polyfit/polyfit.h (99%) create mode 100644 src/utility/CMakeLists.txt create mode 100644 test/CMakeLists.txt create mode 100644 test/README.md create mode 100644 tools/CI.jenkinsfile create mode 100644 tools/Jenkinsfile create mode 100755 tools/deploy_skeleton.sh create mode 100755 tools/download_and_deploy.sh create mode 100755 tools/install_arm_gcc.sh create mode 100755 tools/install_deps.sh create mode 100755 tools/setup_env.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f98657b --- /dev/null +++ b/.clang-format @@ -0,0 +1,289 @@ +--- +# Updated for clang-format 12.0.1, some commented values are there +# for when we update to clang-format 13 +Language: Cpp +Standard: Latest #Cpp20 +# BasedOnStyle: LLVM +# The extra indent or outdent of access modifiers (e.g., public) +AccessModifierOffset: -2 +# Align parameters on the open bracket +# someLongFunction(argument1, +# argument2); +AlignAfterOpenBracket: Align +# Align array column and right justify the columns +#AlignArayOfStructures: Right +# Do not align equals signs of consecutive assignments +AlignConsecutiveAssignments: None +# Do not align the value of consecutive macros +AlignConsecutiveMacros: None +# Do not align the colons of consecutive bitfields +AlignConsecutiveBitFields: None +# Do not align the variable names of consecutive declarations +AlignConsecutiveDeclarations: None +# Align escaped newlines in macros - as far left as possible +AlignEscapedNewlinesLeft: Left +# Horizontally align operands of binary and ternary expressions +# Keeping the operand on the right edge of the upper line +AlignOperands: Align +# Do not align consecutive comments that follow a line of code +AlignTrailingComments: false +# If a function call or braced initializer list doesn’t fit on a line, +# allow putting all arguments onto the next line, even if BinPackArguments is false. +AllowAllArgumentsOnNextLine: true +# If a constructor definition with a member initializer list doesn’t fit on a +# single line, allow putting all member initializers onto the next line, if +# `ConstructorInitializerAllOnOneLineOrOnePerLine` is true. Note that this parameter +# has no effect if `ConstructorInitializerAllOnOneLineOrOnePerLine` is false. +AllowAllConstructorInitializersOnNextLine: true +# If the function declaration doesn’t fit on a line, allow putting all +# parameters of a function declaration onto the next line even if BinPackParameters is false. +AllowAllParametersOfDeclarationOnNextLine: true +# Short blocks (e.g., empty while loop, or a for loop that just continues) are +# never merged into a single line +AllowShortBlocksOnASingleLine: Never +# Short case labels are not contracted into a single line +AllowShortCaseLabelsOnASingleLine: false +# Short enums are not contracted into a single line +AllowShortEnumsOnASingleLine: false +# Short functions are not contracted into a single line +AllowShortFunctionsOnASingleLine: None +# Short If Statements are not contracted into a single line +AllowShortIfStatementsOnASingleLine: Never +# Short lambdas are not contracted into a single line +AllowShortLambdasOnASingleLine: None +# short loops are not contracted to a single line +AllowShortLoopsOnASingleLine: false +# Do not break after the return type +AlwaysBreakAfterReturnType: None +# do not always break before multiline string literals +AlwaysBreakBeforeMultilineStrings: false +# Always break after a template declaration +AlwaysBreakTemplateDeclarations: Yes +# A vector of strings that should be interpreted as attributes/qualifiers instead of identifiers. +# This can be useful for language extensions or static analyzer annotations +AttributeMacros: ['__capability', '__unused'] +# Function call arguments do not always have to have their own line if they don't +# fit on one line +BinPackArguments: true +# Function parameters do not always have to have their own line if they don't +# fit on one line +BinPackParameters: true +# Add one space on each side of the : +BitFieldColonSpacing: Both +# Configure each individual brace in BraceWrapping. +BreakBeforeBraces: Custom +BraceWrapping: + # Opening brace under case label + AfterCaseLabel: true + # Class brace opens on the same line as the class name + AfterClass: true + # Braces are under control statement + AfterControlStatement: Always + # Braces are under enum + AfterEnum: true + # Braces are under function prototype + AfterFunction: true + # Braces are under namespace + AfterNamespace: true + # Braces are under struct keyword + AfterStruct: true + # Braces are under union keyword + AfterUnion: true + # Braces are under extern keyword + AfterExternBlock: true + # Braces are under catch keyword + BeforeCatch: true + # else keyword is placed under if close brace + BeforeElse: true + # Do not place a trailing while loop below the close brace + BeforeWhile: false + # Do not indent wrapped braces + IndentBraces: false + # Empty function body braces are on multiple lines + SplitEmptyFunction: true + # Empty class/struct/union body braces are on multiple lines + SplitEmptyRecord: true + # empty namespace body braces are on multiple lines + SplitEmptyNamespace: true +# For splitting long binary operations, break after the operator +BreakBeforeBinaryOperators: None +# Place concept declaration on a new line +BreakBeforeConceptDeclarations: true +# Break after the ternary operator - ? +BreakBeforeTernaryOperators: false +# Break constructor initializers after the colon and commas +BreakConstructorInitializers: AfterColon +# Break inheritance list after the colon and comma +BreakInheritanceList: AfterColon +# Allow breaking long string literals into multiple lines +BreakStringLiterals: true +# Max Width of a line when formatting +ColumnLimit: 100 +# A regular expression that describes comments with special meaning, +# which should not be split into lines or otherwise changed. +CommentPragmas: '^ IWYU pragma:' +# Each namespace declaration is placed on a new line +CompactNamespaces: false +# Do not require initializers to be on their own lines when breaking +ConstructorInitializerAllOnOneLineOrOnePerLine: false +# The number of characters to use for indentation of constructor initializer +# lists as well as inheritance lists. +ConstructorInitializerIndentWidth: 4 +# Indent width for line continuations. +ContinuationIndentWidth: 4 +# format braced lists as best suited for C++11 braced lists +Cpp11BracedListStyle: true +# Analyze the formatted file for the most used line ending (\r\n or \n). +# UseCRLF is only used as a fallback if none can be derived. +DeriveLineEnding: true +# Do not read the file to derive pointer alignment requirements. Uses PointerAlignment value. +DerivePointerAlignment: false +# Do not completely disable formatting +DisableFormat: false +# Remove all empty lines after access modifiers +#EmptyLineAfterAccessModifier: Never +# Add empty line only when access modifier starts a new logical block. +# Logical block is a group of one or more member fields or functions. +EmptyLineBeforeAccessModifier: LogicalBlock +# add missing namespace end comments for short namespaces and fixes invalid existing ones. +FixNamespaceComments: true +# A vector of macros that should be interpreted as foreach loops instead of as function calls. +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +# Sort each #include block separately (blocks of includes are separated by empty lines) +IncludeBlocks: Preserve +# Regular expressions denoting the different #include categories used for ordering #includes. +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json|catch2|cmocka)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +# Specify a regular expression of suffixes that are allowed in the file-to-main-include mapping. +# use this regex of allowed suffixes to the header stem. +# A partial match is done, so that: - “” means “arbitrary suffix” - “$” means “no suffix” +IncludeIsMainRegex: '$' +# Specify a regular expression for files being formatted that are allowed to be considered +# “main” in the file-to-main-include mapping. +IncludeIsMainSourceRegex: '' +# access modifiers are indented (or outdented) relative to the record members, +# respecting the AccessModifierOffset +#IndentAccessModifiers: false +# Do not indent case blocks one level from case label +IndentCaseBlocks: false +# Do indent case labels within a switch block +IndentCaseLabels: true +# Use AfterExternBlock's indenting rule +IndentExternBlock: AfterExternBlock +# Goto labels are indented to proper level +IndentGotoLabels: true +# Indents preprocessor directives before the hash. +IndentPPDirectives: BeforeHash +# Indent requires clause in a template +IndentRequires: true +# Number of coluns to use for indentation +IndentWidth: 4 +# Indent if a function definition or declaration is wrapped after the type. +IndentWrappedFunctionNames: true +# Remove empty lines at the start of a block +KeepEmptyLinesAtTheStartOfBlocks: false +# Align lambda body relative to the start of the lambda signature +#LambdaBodyIndentation: Signature +# A regular expression matching macros that start a block. +MacroBlockBegin: '' +# A regular expression matching macros that end a block. +MacroBlockEnd: '' +# Maximum number of consecutive empty lines to keep +MaxEmptyLinesToKeep: 1 +# Don’t indent namespaces +NamespaceIndentation: None +# A vector of macros which are used to open namespace blocks +#NamespaceMacros: '' +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +# align pointers: int* ptr +PointerAlignment: Left +# align references like pointers +#ReferenceAlignment: Pointer +# Clang-format will attempt to reflow long comments +ReflowComments: true +# Always have an ending namespace commment +#ShortNamespaceLines: 0 +# Include sorting is alphabetical and case insensitive +SortIncludes: false #CaseInsensitive +# using declarations will be alphabetically sorted +SortUsingDeclarations: true +# Do not insert a space after a C-style cast +SpaceAfterCStyleCast: false +# Do not insert as pace after a logical not (!) +SpaceAfterLogicalNot: false +# Do not insert as pace after the template keyword +SpaceAfterTemplateKeyword: false +# Don't ensure spaces around pointer qualifiers, use PointerAlignment instead +SpaceAroundPointerQualifiers: Default +# Place spaces before assignment operators (=, +=, etc.) +SpaceBeforeAssignmentOperators: true +# Do not place a space befrore a case statement colon +SpaceBeforeCaseColon: false +# Do not place a space befrore a C++11 braced list +SpaceBeforeCpp11BracedList: false +# Do place a space between the constructor and the initializer colon +SpaceBeforeCtorInitializerColon: true +# Place a space between the class and the inheritance colon +SpaceBeforeInheritanceColon: true +# Never place a space between an item and following parens +SpaceBeforeParens: Never +# do not place a space before a range based for loop +SpaceBeforeRangeBasedForLoopColon: false +# do not place a space before square brackets [] +SpaceBeforeSquareBrackets: false +# do not place a space in an empty block +SpaceInEmptyBlock: false +# Do not place a space in empty parens +SpaceInEmptyParentheses: false +# Spaces between end of the code and the start of a // line comment +SpacesBeforeTrailingComments: 1 +# Remove spaces within <> : +SpacesInAngles: false #Never +# Do not add spaces in C-style cast parens +SpacesInCStyleCastParentheses: false +# Do not add spaces around if/for/while/switch conditions +SpacesInConditionalStatement: false +# Do not insert spaces inside container literals +SpacesInContainerLiterals: false +# Do not insert spaces after ( and before ) +SpacesInParentheses: false +# Do not insert spaces after [ and before ] +SpacesInSquareBrackets: false +# Macros which are ignored in front of a statement, as if they were an attribute. +# StatementAttributeLikeMacros: +# A vector of macros that should be interpreted as complete statements. +# StatementMacros: '' +# The number of columns used for tab stops. +TabWidth: 4 +# A vector of macros that should be interpreted as type declarations instead of as function calls. +#TypenameMacros: '' +# use \n for line breaks +UseCRLF: false +# Use tabs whenever we need to fill whitespace that spans at least from one tab stop to the next one. +UseTab: Always +# A vector of macros which are whitespace-sensitive and should not be touched. +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..754e259 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,90 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: true +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '$' +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: true +JavaScriptQuotes: Leave +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: Inner +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: Never +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Always +... diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a16f581 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,12 @@ +*.pdf filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.xlsx filter=lfs diff=lfs merge=lfs -text +*.docx filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.out filter=lfs diff=lfs merge=lfs -text +*.hex filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..796ad28 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,32 @@ +# Expected Behavior + +Please describe the behavior you are expecting + +# Current Behavior + +What is the current behavior? + +# Failure Information (for bugs) + +Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template. + +## Steps to Reproduce + +Please provide detailed steps for reproducing the issue. + +1. step 1 +2. step 2 +3. you get it... + +## Context + +Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions. + +* Firmware Version: +* Operating System: +* SDK version: +* Toolchain version: + +## Failure Logs + +Please include any relevant log snippets or files here. diff --git a/.github/ISSUE_TEMPLATE/FEATURE.md b/.github/ISSUE_TEMPLATE/FEATURE.md new file mode 100644 index 0000000..253f605 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE.md @@ -0,0 +1,27 @@ +--- +name: Feature Request +about: Use this template for requesting new features +title: "[FEATURE NAME]" +labels: enhancement +assignees: finorr +--- + +## Expected Behavior + +Please describe the behavior you are expecting + +## Current Behavior + +What is the current behavior? + +## Sample Code + +If applicable, provide a sample code snippet that demonstrates the gist of feature you're proposing. This can be either from a usage standpoint, or an implementation standpoint. + +## Context + +Please provide any relevant information about your setup, which will help us ensure the requested support will work for you. + +* Project Version: +* Operating System: +* Toolchain version: diff --git a/.github/ISSUE_TEMPLATE/ISSUE.md b/.github/ISSUE_TEMPLATE/ISSUE.md new file mode 100644 index 0000000..a787f37 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ISSUE.md @@ -0,0 +1,48 @@ +--- +name: Issue Report +about: Use this template to report a problem +title: "[VERSION] [PROBLEM SUMMARY]" +labels: bug +assignees: finorr +--- + +## Expected Behavior + +Please describe the behavior you are expecting + +## Current Behavior + +What is the current behavior? + +## Context + +Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions. + +* Project Version: +* Operating System: +* Toolchain: +* Toolchain version: + +## Failure Information (for bugs) + +Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template. + +### Steps to Reproduce + +Please provide detailed steps for reproducing the issue. + +1. step 1 +2. step 2 +3. you get it... + +### Failure Logs + +Please include any relevant log snippets or files here. + +## Checklist + +- [ ] I am running the latest version +- [ ] I checked the documentation and found no answer +- [ ] I checked to make sure that this issue has not already been filed +- [ ] I'm reporting the issue to the correct repository (for multi-repository projects) +- [ ] I have provided sufficient information for the team diff --git a/.github/ISSUE_TEMPLATE/QUESTION.md b/.github/ISSUE_TEMPLATE/QUESTION.md new file mode 100644 index 0000000..133e7e1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/QUESTION.md @@ -0,0 +1,15 @@ +--- +name: Question +about: Use this template to ask a question about the project +title: "[QUESTION SUMMARY]" +labels: question +assignees: finorr +--- + +## Question + +State your question + +## Sample Code + +Please include relevant code snippets or files that provide context for your question. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3ba13e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..9098e60 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,21 @@ +# Description + +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +Fixes # (issue) + +# How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Please also note any relevant details for your test configuration. + +- [ ] Test A +- [ ] Test B + +# Checklist: + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] Any dependent changes have been merged and published in downstream modules diff --git a/.github/PULL_REQUEST_TEMPLATE/ccc.md b/.github/PULL_REQUEST_TEMPLATE/ccc.md new file mode 100644 index 0000000..6587d3f --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/ccc.md @@ -0,0 +1,49 @@ +# Pull Request Template - Code Change Control + +## Description + +Please include a summary of the change and which issue is fixed. Please provide the motivation for why this change is necessary at this stage of the product development cycle. + +Fixes # (issue) + +## Customer Impact + +Please describe any customer facing impact of this change. This can be positive or negative impact. + +## Performance Impact + +Please describe any relevant performance impact of this change. This can be positive or negative impact. How did you characterize/test the performance impact? + +## How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so others can reproduce. Please also list any relevant details for your test configuration. + +- [ ] Test A +- [ ] Test B + +**Hardware Configuration(s) Tested**: + +**Software Configuration(s) Tested**: + +* Operating System: +* Software version: +* Branch: +* Toolchain version: +* SDK version: + +## Reviews + +Please identify two developers to review this change + +- [ ] @personA +- [ ] @personB + +## Checklist: + +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published in downstream modules diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 0000000..62988b9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,42 @@ +# Pull Request Template + +## Description + +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +Fixes # (issue) + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +## How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration + +- [ ] Test A +- [ ] Test B + +**Test Configuration(s)**: + +* Firmware version: +* Hardware: +* Toolchain: +* SDK: + +## Checklist: + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published in downstream modules +- [ ] I have checked my code and corrected any misspellings diff --git a/.gitignore b/.gitignore index c6127b3..e52097a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,52 +1,49 @@ +# Generated Files +**/buildresults/** + +# Sublime-generated Files +*.sublime-workspace + +# VSCode-generated Files +.vscode/** + +######################## +# C / C++ Ignore Rules # +######################## + +# OS Files + +.DS_Store + # Prerequisites *.d -# Object files +# Compiled Object files +*.slo +*.lo *.o -*.ko *.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp # Precompiled Headers *.gch *.pch -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll +# Compiled Dynamic libraries *.so -*.so.* *.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib # Executables *.exe *.out *.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2629ec6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cmake"] + path = cmake + url = git@github.com:embeddedartistry/cmake-buildsystem.git diff --git a/BuildOptions.cmake b/BuildOptions.cmake new file mode 100644 index 0000000..aef87c0 --- /dev/null +++ b/BuildOptions.cmake @@ -0,0 +1,121 @@ +################### +# Project Options # +################### + +include(CMakeDependentOption) +include(CheckIPOSupported) + +check_ipo_supported(RESULT lto_supported) +if("${lto_supported}") + option(ENABLE_LTO + "Enable link-time optimization" + OFF) +endif() + +if(NOT ("${ENABLE_LTO}" AND (${CMAKE_C_COMPILER_ID} STREQUAL Clang OR ${CMAKE_C_COMPILER_ID} STREQUAL AppleClang))) + set(OPTION_DISABLE_BUILTINS_IS_ENABLED True) +else() + set(OPTION_DISABLE_BUILTINS_IS_ENABLED False) +endif() + +option(DISABLE_RTTI + "Disable runtime type information (RTTI) for C++." + OFF) +option(DISABLE_EXCEPTIONS + "Disable exception handling for C++." + OFF) +option(ENABLE_PEDANTIC + "Enable pedantic compiler warnings." + OFF) +option(ENABLE_PEDANTIC_ERROR + "Enable pedantic compiler warnings, and treat them as errors." + OFF) +option(DISABLE_STACK_PROTECTION + "Disable stack smashing protection (-fno-stack-protector)." + ON) +CMAKE_DEPENDENT_OPTION(PROJECTVARNAME_BUILD_TESTING + "Enable testing even when this project is used as an external project." + OFF + "NOT CMAKE_CROSSCOMPILING" OFF) +CMAKE_DEPENDENT_OPTION(DISABLE_BUILTINS + "Disable compiler builtins (-fno-builtin)." + OFF + "${OPTION_DISABLE_BUILTINS_IS_ENABLED}" + ON) + +################### +# Process Options # +################### + +if((NOT CMAKE_CROSSCOMPILING) AND BUILD_TESTING AND + (PROJECTVARNAME_BUILD_TESTING OR (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME))) + message("Enabling tests.") + set(PROJECTVARNAME_TESTING_IS_ENABLED ON CACHE INTERNAL "Logic that sets whether testing is enabled on this project") +endif() + +if("${ENABLE_LTO}") + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) +endif() + +if(DISABLE_RTTI) + add_compile_options(-fno-rtti) +endif() + +if(DISABLE_EXCEPTIONS) + add_compile_options(-fno-exceptions -fno-unwind-tables) +endif() + +if(DISABLE_BUILTINS) + add_compile_options(-fno-builtin) +endif() + +if(DISABLE_STACK_PROTECTION) + add_compile_options(-fno-stack-protector) +endif() + +if(ENABLE_PEDANTIC) + add_compile_options(-pedantic) +endif() + +if(ENABLE_PEDANTIC_ERROR) + add_compile_options(-pedantic-error) +endif() + +############################################## +# Default Settings for CMake Cache Variables # +############################################## + +# Set a default build type if none was specified +set(default_build_type "RelWithDebInfo") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build." + FORCE + ) + # Set the possible values of build type for cmake-gui/ccmake + set_property(CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo" + ) +endif() + +set(default_pic ON) +if("${CMAKE_POSITION_INDEPENDENT_CODE}" STREQUAL "") + message(STATUS "Setting PIC for all targets to '${default_pic}' as no value was specified.") + set(CMAKE_POSITION_INDEPENDENT_CODE ${default_pic} CACHE + BOOL "Compile all targets with -fPIC" + FORCE + ) +endif() + +set(default_shared_libs OFF) +if("${BUILD_SHARED_LIBS}" STREQUAL "") + message(STATUS "Setting 'build shared libraries' to '${default_shared_libs}' as no value was specified.") + set(BUILD_SHARED_LIBS ${default_shared_libs} CACHE + BOOL "Compile shared libraries by default instead of static libraries." + FORCE + ) +endif() + +# Export compile_commands.json file. +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/CMakeLists.txt b/CMakeLists.txt index f9dc744..b3d54dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,16 +1,104 @@ -cmake_minimum_required(VERSION 3.10) -project(MyProject C) +cmake_minimum_required(VERSION 3.17) +project(polyfit + VERSION 0.1 + DESCRIPTION "POLYFIT" + LANGUAGES C CXX ASM) -set(CMAKE_C_STANDARD 11) +set_property(GLOBAL PROPERTY C_STANDARD 11) +set_property(GLOBAL PROPERTY CXX_STANDARD 20) -# Source files -set(SOURCES demo.c polyFit.c) +################# +# Build Modules # +################# -# Executable name -set(TARGET demo) +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR PROJECTVARNAME_BUILD_TESTING) + include(CTest) +endif() -# Add the executable -add_executable(${TARGET} ${SOURCES}) +# Define and Process Project Options +include(BuildOptions.cmake) -# Link the math library -target_link_libraries(${TARGET} m) +# Dependency manager +include(cmake/CPM.cmake) +# Improved functions for checking compiler/linker flag support +include(cmake/compiler/CheckAndApplyFlags.cmake) +# Adds a function for generating a linker map +include(cmake/linker/map.cmake) +# Overrides add_executable so that linker script dependencies are registered automatically +include(cmake/linker/AddExecutableWithLinkerScriptDep.cmake) +# Provides functions to convert ELF files into .bin and .hex +include(cmake/Conversions.cmake) +# Enable code coverage analysis support +include(cmake/analysis/coverage.cmake) +# Enable code sanitizer build support +include(cmake/analysis/sanitizers.cmake) + +# Enable CMocka support if testing is enabled +if(PROJECTVARNAME_TESTING_IS_ENABLED) + include(cmake/test/cmocka.cmake) +endif() + +# Enable Catch2 Support if testing is enabled +if(PROJECTVARNAME_TESTING_IS_ENABLED) + include(cmake/test/catch2.cmake) +endif() + +# Specifies default compiler flags for the project +include(cmake/compiler/DefaultCompilerSettings.cmake) +# Specifies default linker flags for the project +include(cmake/linker/DefaultLinkerSettings.cmake) + +# Define Packaging Rules +include(Packaging.cmake) + +######################### +# External Dependencies # +######################### + +# You can set an ETL_PROFILE variable option to control the profile header to include +# The library is called etl +CPMAddPackage( + NAME etl + GIT_REPOSITORY git@github.com:ETLCPP/etl.git + GIT_TAG master + OPTIONS + "BUILD_TESTS OFF" +) + +########################## +# Enable Static Analysis # +########################## + +# Provides cppcheck targets and an option to compile with cppcheck analysis +include(cmake/analysis/cppcheck.cmake) +# Provides clang-tidy targets and and option to compile with clang-tidy analysis +include(cmake/analysis/clang-tidy.cmake) + +####################### +# Process Source Tree # +####################### + +add_subdirectory(src) + +##################### +# Process Test Tree # +##################### + +add_subdirectory(test) + +################### +# Tooling Targets # +################### + +# Provides clang-format build targets +include(cmake/format/clang-format.cmake) +# Provides complexity analysis targets +include(cmake/analysis/complexity.cmake) +# Defines code coverage analysis targets +enable_coverage_targets(polyfit_tests) +# Provides Doxygen documentation generation target +include(cmake/documentation/doxygen.cmake) +# Provides SLOCCount targets +include(cmake/analysis/sloccount.cmake) +# Provides vale documentation linting target +include(cmake/analysis/vale.cmake) diff --git a/LICENSE b/LICENSE index 905c485..261eeb9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,201 @@ -MIT License - -Copyright (c) 2024 Fin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ce262e3 --- /dev/null +++ b/Makefile @@ -0,0 +1,203 @@ +# you can set this to 1 to see all commands that are being run +VERBOSE ?= 0 + +ifeq ($(VERBOSE),1) +export Q := +export VERBOSE := 1 +else +export Q := @ +export VERBOSE := 0 +endif + +BUILDRESULTS ?= buildresults +CONFIGURED_BUILD_DEP = $(BUILDRESULTS)/build.ninja + +# This skeleton is built for CMake's Ninja generator +export CMAKE_GENERATOR=Ninja + +OPTIONS ?= +INTERNAL_OPTIONS = + +CPM_CACHE?=$(HOME)/CPM_Cache +ifneq ($(CPM_CACHE),) + INTERNAL_OPTIONS += -DCPM_SOURCE_CACHE=$(CPM_CACHE) +endif + +LTO ?= 0 +ifeq ($(LTO),1) + INTERNAL_OPTIONS += -DENABLE_LTO=ON +endif + +CROSS ?= +ifneq ($(CROSS),) + INTERNAL_OPTIONS += -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/cross/$(CROSS).cmake +endif + +NATIVE ?= +ifneq ($(NATIVE),) + INTERNAL_OPTIONS += -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/native/$(NATIVE).cmake +endif + +BUILD_TYPE ?= +ifneq ($(BUILD_TYPE),) + INTERNAL_OPTIONS += -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) +endif + +SANITIZER ?= +ifneq ($(SANITIZER),) + INTERNAL_OPTIONS += -DUSE_SANITIZER=$(SANITIZER) +endif + +all: default + +.PHONY: default +default: | $(CONFIGURED_BUILD_DEP) + $(Q)ninja -C $(BUILDRESULTS) + +.PHONY: test +test: default + $(Q)cd $(BUILDRESULTS); ctest + +.PHONY: docs +docs: | $(CONFIGURED_BUILD_DEP) + $(Q)ninja -C $(BUILDRESULTS) docs + +.PHONY: package +package: default + $(Q)ninja -C $(BUILDRESULTS) package + $(Q)ninja -C $(BUILDRESULTS) package_source + +.PHONY: cppcheck +cppcheck: | $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) cppcheck + +.PHONY: cppcheck-xml +cppcheck-xml: | $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) cppcheck-xml + +.PHONY: complexity +complexity: | $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) complexity + +.PHONY: complexity-xml +complexity-xml: | $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) complexity-xml + +.PHONY: complexity-full +complexity-full: | $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) complexity-full + +.PHONY: tidy +tidy: $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) tidy + +.PHONY: format +format: $(CONFIGURED_BUILD_DEP) + $(Q)ninja -C $(BUILDRESULTS) format + +.PHONY : format-patch +format-patch: $(CONFIGURED_BUILD_DEP) + $(Q)ninja -C $(BUILDRESULTS) format-patch + +.PHONY: scan-build +scan-build: + $(Q) scan-build cmake -B $(BUILDRESULTS)/scan-build $(OPTIONS) $(INTERNAL_OPTIONS) + $(Q) ninja -C $(BUILDRESULTS)/scan-build + +.PHONY: coverage +coverage: + $(Q) cmake -B $(BUILDRESULTS)/coverage -DCMAKE_BUILD_TYPE=Debug -DENABLE_COVERAGE_ANALYSIS=ON $(OPTIONS) $(INTERNAL_OPTIONS) + $(Q) ninja -C $(BUILDRESULTS)/coverage + $(Q) cd $(BUILDRESULTS)/coverage; ctest + $(Q) ninja -C $(BUILDRESULTS)/coverage coverage + +.PHONY: sloccount +sloccount: $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) sloccount + +.PHONY: sloccount-full +sloccount-full: $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) sloccount-full + +.PHONY: sloccount-report +sloccount-report: $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) sloccount-report + +.PHONY: sloccount-report-full +sloccount-full-report: $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) sloccount-report-full + +.PHONY: vale +vale: $(CONFIGURED_BUILD_DEP) + $(Q) ninja -C $(BUILDRESULTS) vale + +# Runs whenever the build has not been configured successfully +$(CONFIGURED_BUILD_DEP): + $(Q)cmake -B $(BUILDRESULTS) $(OPTIONS) $(INTERNAL_OPTIONS) + +# Manually Reconfigure a target, esp. with new options +.PHONY: reconfig +reconfig: + $(Q) cmake -B $(BUILDRESULTS) $(OPTIONS) $(INTERNAL_OPTIONS) + +.PHONY: clean +clean: + $(Q) if [ -d "$(BUILDRESULTS)" ]; then ninja -C $(BUILDRESULTS) clean; fi + +.PHONY: distclean +distclean: + $(Q) rm -rf $(BUILDRESULTS) + +.PHONY : help +help : + @echo "usage: make [OPTIONS] " + @echo " Options:" + @echo " > VERBOSE Show verbose output for Make rules. Default 0. Enable with 1." + @echo " > BUILDRESULTS Directory for build results. Default buildresults." + @echo " > OPTIONS Configuration options to pass to a build. Default empty." + @echo " > LTO Enable LTO builds. Default 0. Enable with 1." + @echo " > CROSS Enable a Cross-compilation build. " + @echo " Pass the cross-compilation toolchain name without a path or extension." + @echo " Example: make CROSS=cortex-m3" + @echo " For supported toolchains, see cmake/toolchains/cross/" + @echo " > NATIVE Use an alternate toolchain on your build machine. " + @echo " Pass the toolchain name without a path or extension." + @echo " Example: make CROSS=gcc-9" + @echo " For supported toolchains, see cmake/toolchains/native/" + @echo " > CPM_CACHE Specify the path to the CPM source cache." + @echo " Set the variable to an empty value to disable the cache." + @echo " > BUILD_TYPE Specify the build type (default: RelWithDebInfo)" + @echo " Option are: Debug Release MinSizeRel RelWithDebInfo" + @echo " > SANITIZER Compile with support for a Clang/GCC Sanitizer." + @echo " Options are: none (default), address, thread, undefined, memory," + @echo " leak, and 'address,undefined' as a combined option" + @echo "Targets:" + @echo " default: Builds all default targets ninja knows about" + @echo " test: Build and run unit test programs" + @echo " docs: Generate documentation" + @echo " package: Build the project, generates docs, and create a release package" + @echo " clean: cleans build artifacts, keeping build files in place" + @echo " distclean: removes the configured build output directory" + @echo " reconfig: Reconfigure an existing build output folder with new settings" + @echo "Static Analysis:" + @echo " cppcheck: runs cppcheck" + @echo " cppcheck-xml: runs cppcheck and generates an XML report (for build servers)" + @echo " Code Formating:" + @echo " format: runs clang-format on codebase" + @echo " format-patch: generates a patch file with formatting changes" + @echo " Static Analysis:" + @echo " cppcheck: runs cppcheck" + @echo " cppcheck-xml: runs cppcheck and generates an XML report (for build servers)" + @echo " scan-build: runs clang static analysis" + @echo " complexity: runs complexity analysis with lizard, only prints violations" + @echo " complexity-full: runs complexity analysis with lizard, prints full report" + @echo " complexity-xml: runs complexity analysis with lizard, generates XML report" + @echo " (for build servers)" + @echo " coverage: runs code coverage analysis and generates an HTML & XML reports" + @echo " tidy: runs clang-tidy linter" + @echo " sloccount: Run SLOCCount analysis on project." + @echo " sloccount: Run SLOCCount analysis on project with detailed output." + @echo " sloccount-report: Run SLOCCount analysis on project and save the results to a file." + @echo " sloccount-report-full: Run SLOCCount analysis on project with detailed output" + @echo " save the results to a file." + @echo " vale: Run vale documentation linting." diff --git a/Packaging.cmake b/Packaging.cmake new file mode 100644 index 0000000..6d64340 --- /dev/null +++ b/Packaging.cmake @@ -0,0 +1,30 @@ +#################### +# Packaging Module # +#################### + +### General Configuration ### + +set(CPACK_PACKAGE_VENDOR "Embedded Artistry") +set(CPACK_GENERATOR "ZIP;TBZ2") +set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/packages") + +set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CMAKE_SYSTEM_PROCESSOR}") +if(CPU_NAME) + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CPU_NAME}") +endif() +if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Generic") + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CMAKE_SYSTEM_NAME}") +endif() +set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CMAKE_PROJECT_VERSION}") + +### Source Packaging Configuration ### + +set(CPACK_SOURCE_GENERATOR "ZIP;TBZ2") +set(CPACK_SOURCE_IGNORE_FILES + "${CMAKE_BINARY_DIR}" + ".DS_Store" + "/.git*/" +) + +### INCLUDE ALL SETTINGS BEFORE THIS LINE +include(CPack) diff --git a/README.md b/README.md index 4a8034b..51d3a9e 100644 --- a/README.md +++ b/README.md @@ -5,21 +5,36 @@ [![GitHub issues](https://img.shields.io/github/issues/FinOrr/polyfit.svg)](https://github.com/FinOrr/polyfit/issues) [![GitHub pull requests](https://img.shields.io/github/issues-pr/FinOrr/polyfit.svg)](https://github.com/FinOrr/polyfit/pulls) - ## Overview **PolyFit** is a C library designed to facilitate accurate polynomial fitting for curve approximation, allowing for interpolation and extrapolation of data points. With just a few input datapoints, you can model your system quickly and efficiently. +## Table of Contents + +1. [Use Case Scenarios](#use-case-scenarios) +2. [Project Status](#project-status) +3. [Getting Started](#getting-started) + 1. [Requirements](#requirements) + 1. [git-lfs](#git-lfs) + 1. [CMake Build System](#cmake-build-system) + 2. [Getting the Source](#getting-the-source) + 3. [Building](#building) + 4. [Testing](#testing) +5. [Documentation](#documentation) +6. [Need Help?](#need-help) +7. [Contributing](#contributing) +8. [Further Reading](#further-reading) +9. [Authors](#authors) +10. [License](#license) +11. [Acknowledgments](#acknowledgements) + ## Use Case Scenarios -Sound a bit asbtract? No worries, here's some examples of where PolyFit might solve a problem you have. +Sound a bit asbtract? No worries, here's some examples of where PolyFit can help: **Curve Fitting in Data Analysis** - In climate science research, polynomial curve fitting is applied to analyse historical temperature data and predict future climate trends, aiding in understanding global warming patterns. -**Image Processing and Computer Vision** -- Polynomials are utilised in computer vision tasks, such as facial recognition systems, where they help map facial features accurately for identification purposes. - **Signal Processing and Filtering** - Biomedical engineers use polynomial filters to remove noise from electroencephalogram (EEG) signals within neuroscience research, improving the detection of brainwave patterns and facilitating the diagnosis of neurological disorders. @@ -33,82 +48,222 @@ Sound a bit asbtract? No worries, here's some examples of where PolyFit might so - map building and refinement; and - sensor calibration. -**Function Approximation in Optimisation** -- Civil engineers use polynomial approximations to model stress-strain relationships in structural materials for bridge design. By approximating complex material behavior with polynomials, engineers can optimise structural designs for safety and durability under various loading conditions. - **Transform Functions and Control Systems** - Polynomial models are vital in representing system transfer functions, which describe the relationship between inputs and outputs of a dynamic system. By mapping polynomials to transfer functions, engineers can model the behavior of diverse systems across various domains, including aerospace, automotive, and industrial control. -- For instance, in control systems engineering, polynomials are transformed into transfer functions to characterise the dynamics of physical systems, such as aircraft, vehicles, and manufacturing processes! -- These transfer functions capture the system's response to inputs and enable engineers to design control algorithms to achieve desired performance objectives, such as stability, responsiveness, and robustness. -- With transfer functions derived from polynomials, engineers can perform advanced control systems analysis techniques, such as Root-Locus, frequency response analysis, and pole-zero analysis. + +- Engineers can use transfer functions derived from polynomials to perform advanced control systems analysis techniques, such as Root-Locus, freq response analysis, and pole-zero analysis to achieve desired performance objectives, such as stability, responsiveness, and robustness. **Control System Applications** - In industrial automation, polynomial controllers regulate motors by translating input commands into precise motor outputs. - By applying specific inputs and measuring corresponding outputs, such as speed or torque, engineers optimise manufacturing processes. - For example, in controlling fluid pump outputs, polynomial controllers enable adjustments to achieve desired pressure levels or flow rates, enhancing efficiency and product quality. +**[Back to top](#table-of-contents)** + ## Features - Polynomial fitting for curve approximation. + - Interpolation and extrapolation functionality for predicting additional data points. + - Lightweight and easy-to-integrate into existing C projects. -## Usage +**[Back to top](#table-of-contents)** + +# Project Status + +The current system requires the user to specify the desired order of polynomial to be fit to the data. +Future releases will focus on auto-detecting the most suitable, lowest-order polynomial. + +**[Back to top](#table-of-contents)** + +## Getting Started + +### Requirements -### Installation +At a minimum you will need: -Clone the repository: +* [`git-lfs`](https://git-lfs.github.com), which is used to store binary files in this repository +* [CMake](#cmake-build-system) is the build system +* Some kind of compiler for your target system. + - This repository has been tested with: + - gcc-7, gcc-8, gcc-9 + - arm-none-eabi-gcc + - Apple clang + - Mainline clang -```bash -git clone https://github.com/FinOrr/polyfit.git +#### git-lfs + +This project stores some files using [`git-lfs`](https://git-lfs.github.com). + +To install `git-lfs` on Linux: + +``` +sudo apt install git-lfs +``` + +To install `git-lfs` on OS X: + +``` +brew install git-lfs ``` -Copy the polyFit.c and polyFit.h files into your project directory. +Additional installation instructions can be found on the [`git-lfs` website](https://git-lfs.github.com). + +#### CMake Build System -Include the polyFit.h header file in your source files where you want to use the polynomial regression functionality. +The official way to install CMake is to use the pre-compiled binaries and installers on the [CMake download page](https://cmake.org/download/). You can also [compile CMake from source](https://cmake.org/install/). CMake can also be installed through popular package managers, although they may be slightly behind the latest release available on the website. -```c -#include "polyFit.h" +You can install CMake with `apt` on Linux/WSL: + +``` +sudo apt-get install cmake ``` -### Example +> **Note:** Does this not work? You may need to add an [apt repository](https://apt.kitware.com/). -See the demo.c program for example usage. -To build the demo, you'll need CMake installed. +OS X users can install CMake using [Homebrew](homebrew): -Open a terminal, navigate to the directory containing your source files and the CMakeLists.txt, and run the following commands: +``` +brew install cmake +``` + +You can also use Python's `pip` to install CMake: + +``` +$ pip3 install cmake +``` + +Make is the default backend for CMake, but our Makefile interface defaults to Ninja. Ninja is similar in purpose to Make, but provides better performance. + +To install Ninja on Linux & WSL: + +``` +$ sudo apt install ninja-build +``` + +To install on OSX: + +``` +$ brew install ninja +``` + + +**[Back to top](#table-of-contents)** + +### Getting the Source + +This project uses [`git-lfs`](https://git-lfs.github.com), so please install it before cloning. If you cloned prior to installing `git-lfs`, simply run `git lfs pull` after installation. -```bash -mkdir build -cd build -cmake .. +This project is hosted on GitHub. You can clone the project directly using this command: + +``` +git clone --recursive git@github.com:finorr/polyfit.git +``` + +If you don't clone recursively, be sure to run the following command in the repository or your build will fail: + +``` +git submodule update --init ``` -This will generate the build files. Once the files are generated, you can build your project by running: -```bash +**[Back to top](#table-of-contents)** + +### Building + +If Make is installed, the library can be built by issuing the following command: + +``` make ``` -This will compile your source files and create the executable. If you want to clean the generated files, you can run: -```bash +This will build all targets for your current architecture. + +You can clean builds using: + +``` make clean ``` -The resulting executable will be in the build directory. +You can eliminate the generated `buildresults` folder using: + +``` +make distclean +``` + +You can also use `CMake` directly for compiling. + +Create a build output folder: + +``` +cmake -B buildresults +``` + +And build all targets by running + +``` +ninja -C buildresults +``` + +Cross-compilation is handled using CMake toolchain files. Example files are included in the [`cmake/toolchains/cross`](cmake/toolchains/cross/) folder. You can write your own cross files for your specific processor by defining the toolchain, compilation flags, and linker flags. These settings will be used to compile the project. + +Cross-compilation must be configured using the CMake command when creating the build output folder. For example: + +``` +cmake -B buildresults -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/cross/cortex-m3.cmake +``` + +Following that, you can run `make` (at the project root) or `ninja` to build the project. + +Tests will not be cross-compiled. They will only be built for the native platform. + +**[Back to top](#table-of-contents)** + +### Testing + +The tests for this project are written in CMocka and Catch, which are included as external dependencies and does not need to be installed on your system. You can run the tests by issuing the following command: + +``` +make test +``` + +By default, test results are generated for use by the CI server and are formatted in JUnit XML. The test results XML files can be found in `buildresults/test/`. + +**[Back to top](#table-of-contents)** ## Documentation -Detailed documentation can be found in the [Wiki](https://github.com/FinOrr/polyfit/wiki). +Documentation can be built locally by running the following command: + +``` +make docs +``` + +Documentation can be found in `buildresults/docs`, and the root page is `index.html`. + +**[Back to top](#table-of-contents)** + +## Need help? + +For any inquiries or support, please use the [Issues](https://github.com/FinOrr/polyfit/issues) page. + +If you need further assistance or have any questions, please file a GitHub issue or [send me an email](mailto:3ikxlgcis@mozmail.com). ## Contributing -Contributions are welcome! Please check the [Contribution Guidelines](CONTRIBUTING.md) before making a pull request. +If you are interested in contributing to this project, please read our [contributing guidelines](docs/CONTRIBUTING.md). + +## Authors + +* Polyfit source code - **[Fin Orr](https://github.com/finorr)** +* CMake Repo Design - **[Phillip Johnston](https://github.com/phillipjohnston)** ## License -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. - -## Contact +See the [LICENSE](LICENSE) file for licensing details. -For any inquiries or support, please use the [Issues](https://github.com/FinOrr/polyfit/issues) page. - +## Acknowledgments + +This repository was built using the [CMake repository template](https://github.com/embeddedartistry/cmake-project-skeleton) from the team at Embedded Artistry. + +**[Back to top](#table-of-contents)** diff --git a/demo.c b/demo.c deleted file mode 100644 index 220ed59..0000000 --- a/demo.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include "polyFit.h" - -int main(void) { - //////////////////////////////////////////////////// - // Demo: Modelling an x^2 parabola - // There is typically 4 steps to using the library. - //////////////////////////////////////////////////// - - // Step 1: Initialise the polynomial - // You'll need to define the degree of the polynomial. This will be optimised - // in the future. For now, we need to manually assign the degree ('order') of - // the polynomial In this example we want to fit an x^3 curve, so we use - // degree=2. - int32_t degree = 3; - Polynomial *poly = initPolynomial(degree); - - // Step 2: Fit the polynomial coefficients to your data. - // You will need an input array of samples (x and y components), these are - // used used to fit the polynomial. In this demo, we're modelling an x^3 - // parabola, so let's record the first 4 components of this curve. - float xData[] = {0, 2, 4, 5}; - float yData[] = {0, 8, 64, 125}; - - // Basic validation, confirm each x sample has a corresponding y sample. - int32_t numXSamples = (int32_t)(sizeof(xData) / sizeof(xData[0])); - int32_t numYSamples = (int32_t)(sizeof(yData) / sizeof(yData[0])); - if (numXSamples == numYSamples) { - // Now we fit the polynomial to the dataset with the following function call - leastSquaresPolynomialRegression(xData, yData, numXSamples, degree, poly); - } else { - // Not the most gracious of error handling, but you get the idea. - exit(EXIT_FAILURE); - } - - // Step 3: Now you can interpolate or extrapolate any point on the curve. - // Demo output text showing extrapolation / interpolation of the x^3 curve. - printf("Testing polynomial for various x values:\n"); - printf("| %-10s | %-10s |\n", "x", "y (y=x^2)"); - printf("|------------|------------|\n"); - - // To find a data point on the curve, pass the polynomial and the desired x- - // component to the evaluatePolynomial() function. Let's test 20 locations: - for (float x = -10; x <= 10; x += 1) { - float y = evaluatePolynomial(poly, x); - printf("| %-10.2f | %-10.2f |\n", x, y); - } - - // Step 4: Free the memory when we're done to prevent memory leaks. - freePolynomial(poly); - - return (EXIT_SUCCESS); -} diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..cae100e --- /dev/null +++ b/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,5 @@ +# Contributor Code of Conduct + +The latest version of the [Embedded Artistry Code of Conduct](https://embeddedartistry.com/fieldatlas/embedded-artistry-code-of-conduct/) is found on [our website](https://embeddedartistry.com/fieldatlas/embedded-artistry-code-of-conduct/). + +All contributors and community members are expected to adhere to [the Code](https://embeddedartistry.com/fieldatlas/embedded-artistry-code-of-conduct/). diff --git a/CONTRIBUTING.md b/docs/CONTRIBUTING.md similarity index 95% rename from CONTRIBUTING.md rename to docs/CONTRIBUTING.md index f5968bf..69e5010 100644 --- a/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to PolyFit Extrapolator -Thank you for your interest in contributing to PolyFitExtrapolator! +Thank you for your interest in contributing to PolyFit! By contributing to this project, you help make it better. ## How to Contribute diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..172d294 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(utility) +add_subdirectory(lib) +add_subdirectory(app) diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt new file mode 100644 index 0000000..23c085b --- /dev/null +++ b/src/app/CMakeLists.txt @@ -0,0 +1,10 @@ +add_executable(APP) +target_sources(APP PRIVATE demo.c) +target_link_libraries(APP PRIVATE example utilities) +target_linker_map(APP) + +# Apply unconditional private flags here +list(APPEND APP_private_compile_flags + "-Wno-unknown-pragmas" +) +apply_supported_compiler_flags(C APP PRIVATE APP_private_compile_flags) diff --git a/src/app/demo.c b/src/app/demo.c new file mode 100644 index 0000000..71b406c --- /dev/null +++ b/src/app/demo.c @@ -0,0 +1,90 @@ +#include +#include + +void basicDemo(void); + +int main(void) +{ + basicDemo(); + return (EXIT_SUCCESS); +} + +/** + * @brief Demonstrates modelling an x^2 parabola using the library. + * + * This example illustrates the four main steps involved in using the library to fit a polynomial to + * data and evaluate it. + */ +void basicDemo(void) +{ + /** + * @brief Initializes the polynomial with a given degree. + * + * This function allocates memory and sets up the internal state of the polynomial + * object. The degree parameter specifies the highest power of the polynomial. + * + * @param degree The degree of the polynomial. + * + * @return A pointer to the newly created polynomial object, or NULL on failure. + */ + int32_t degree = 3; + Polynomial* poly = initPolynomial(degree); + + /** + * @brief Fits the polynomial coefficients to a given dataset. + * + * This function uses the least squares method to fit the polynomial coefficients + * to a set of sample points provided in the xData and yData arrays. + * + * @param xData An array of x-coordinates of the sample points. + * @param yData An array of y-coordinates of the sample points. + * @param numSamples The number of samples in the dataset. + * @param degree The degree of the polynomial. + * @param poly The polynomial object to fit. + */ + float xData[] = {0, 2, 4, 5}; + float yData[] = {0, 8, 64, 125}; + + int32_t numXSamples = (int32_t)(sizeof(xData) / sizeof(xData[0])); + int32_t numYSamples = (int32_t)(sizeof(yData) / sizeof(yData[0])); + if(numXSamples == numYSamples) + { + leastSquaresPolynomialRegression(xData, yData, numXSamples, degree, poly); + } + else + { + // Handle error gracefully + exit(EXIT_FAILURE); + } + + /** + * @brief Evaluates the polynomial at a given x-value. + * + * This function calculates the corresponding y-value for a given x-coordinate + * based on the fitted polynomial coefficients. + * + * @param poly The fitted polynomial object. + * @param x The x-coordinate to evaluate. + * + * @return The calculated y-value. + */ + printf("Testing polynomial for various x values:\n"); + printf("| %-10s | %-10s |\n", "x", "y (y=x^2)"); + printf("|------------|------------|\n"); + + for(float x = -10; x <= 10; x += 1) + { + float y = evaluatePolynomial(poly, x); + printf("| %-10.2f | %-10.2f |\n", x, y); + } + + /** + * @brief Frees the memory allocated for the polynomial object. + * + * This function deallocates the memory used by the polynomial object to + * prevent memory leaks. + * + * @param poly The polynomial object to free. + */ + freePolynomial(poly); +} diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt new file mode 100644 index 0000000..921e5aa --- /dev/null +++ b/src/lib/CMakeLists.txt @@ -0,0 +1,26 @@ +# Libraries live here +# +# This are larger modules with a cohesive set of features used to accomplish some +# purpose, e.g. WolfSSL or liblz4. Smaller, single-purpose modules should live in utilities. + +# Save the library directory path for use with our `add_library` call below +set(LIBRARY_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}) + +# All targets in the lib tree should be included with a directory prefix: +# #include +# To accomplish this, we automatically set `target_include_directories` for library +# targets so this scheme can be used. +# +# Library targets themselves should NOT set public/interface includes within the library tree +function(add_library target) + # Forward all arguments to the orginal add_library + _add_library(${target} ${ARGN}) + # Ensure this directory is included as an interface include + target_include_directories(${target} INTERFACE ${LIBRARY_ROOT_DIR}) +endfunction() + +############# +# Libraries # +############# + +add_subdirectory(polyfit) diff --git a/src/lib/polyfit/CMakeLists.txt b/src/lib/polyfit/CMakeLists.txt new file mode 100644 index 0000000..1488e28 --- /dev/null +++ b/src/lib/polyfit/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(polyfit) +target_sources(polyfit PRIVATE polyfit.c) diff --git a/polyFit.c b/src/lib/polyfit/polyfit.c similarity index 99% rename from polyFit.c rename to src/lib/polyfit/polyfit.c index 26c31ef..d602082 100644 --- a/polyFit.c +++ b/src/lib/polyfit/polyfit.c @@ -1,6 +1,6 @@ /** ****************************************************************************** - * @file polyFit.c + * @file polyfit.c * @brief Source file for fitting polynomials to datasets. ****************************************************************************** * @attention @@ -13,7 +13,7 @@ ****************************************************************************** */ -#include "polyFit.h" +#include "polyfit.h" /** * @brief Initialise a polynomial and return a pointer to it. diff --git a/polyFit.h b/src/lib/polyfit/polyfit.h similarity index 99% rename from polyFit.h rename to src/lib/polyfit/polyfit.h index 8236c1b..866cf2f 100644 --- a/polyFit.h +++ b/src/lib/polyfit/polyfit.h @@ -1,6 +1,6 @@ /** ****************************************************************************** - * @file polyFit.h + * @file polyfit.h * @brief Header file for fitting polynomials to datasets. ****************************************************************************** */ diff --git a/src/utility/CMakeLists.txt b/src/utility/CMakeLists.txt new file mode 100644 index 0000000..31ff70d --- /dev/null +++ b/src/utility/CMakeLists.txt @@ -0,0 +1,15 @@ +# Utilities live here +# (standalone modules with singular functionality implemented in a standalone manner) +# +# Utility modules are expected to live in subdirectories of this folder, so they +# are included via `#include +# +# The default build structure is for a header-only libraries. +# +# If you want to add source files, remove the `INTERFACE` option from `add_library`. +# And make the INTERFACE option in `target_include_directories` PUBLIC. +# Then, you can use `add_subdirectory` and call `target_sources(utilities PRIVATE ...)` +# to add files to the library. + +add_library(utilities INTERFACE) +target_include_directories(utilities INTERFACE .) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..3f2adac --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,32 @@ +if(PROJECTVARNAME_TESTING_IS_ENABLED) + ################ + # CMocka Tests # + ################ + add_executable(MYPROJECT_tests) + target_include_directories(MYPROJECT_tests PRIVATE .) + target_link_libraries(MYPROJECT_tests PRIVATE cmocka_dep) + target_sources(MYPROJECT_tests PRIVATE + main.c + test_suite.c + ) + target_linker_map(MYPROJECT_tests) + + list(APPEND desired_MYPROJECT_test_flags + "-Wno-unused-parameter" + ) + apply_supported_compiler_flags(C MYPROJECT_tests PRIVATE desired_MYPROJECT_test_flags) + + # This registers the test and defines testing targets + register_cmocka_test(MYPROJECT.Test MYPROJECT_tests) + + ################ + # Catch2 Tests # + ################ + add_executable(MYPROJECT_catch_tests) + target_link_libraries(MYPROJECT_catch_tests PRIVATE catch2_dep) + target_sources(MYPROJECT_catch_tests PRIVATE + catch2_test_case.cpp + ) + + register_catch2_test(MYPROJECT.Catch2.Test MYPROJECT_catch_tests) +endif(PROJECTVARNAME_TESTING_IS_ENABLED) diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..18918e7 --- /dev/null +++ b/test/README.md @@ -0,0 +1 @@ +The `test` folder contains tests and testing frameworks. diff --git a/tools/CI.jenkinsfile b/tools/CI.jenkinsfile new file mode 100644 index 0000000..ec9819a --- /dev/null +++ b/tools/CI.jenkinsfile @@ -0,0 +1,427 @@ +#!groovy +@Library('jenkins-pipeline-lib@pj/new-bs') _ + +pipeline +{ + agent any + stages + { + stage('Clean') + { + when + { + expression + { + /* + * If the previous build suceeeded (unstable means test failed but build passed) + * then we continue on in CI mode. If the previous build failed we want to + * start with a clean environment. This is done to reduce manual user interation. + */ + return !(didLastBuildSucceed()) + } + } + steps + { + echo('Previous build failed: Running a clean build.') + sh 'make distclean' + } + } + stage('Format') + { + steps + { + clangFormat() + } + } + stage('Build for Clang') + { + steps + { + sh 'make' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + clang(), + ] + ) + } + } + } + stage('Build for GCC-9') + { + steps + { + sh 'make NATIVE=gcc-9 BUILDRESULTS=buildresults/gcc-9' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/gcc-9', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + gcc(id:'gcc-9', name: 'gcc-9'), + ] + ) + } + } + } + stage('Build for GCC-8') + { + steps + { + sh 'make NATIVE=gcc-8 BUILDRESULTS=buildresults/gcc-8' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/gcc-8/', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + gcc(id: 'gcc-8', name: 'gcc-8'), + ] + ) + } + } + } + stage('Build for GCC-7') + { + steps + { + sh 'make NATIVE=gcc-7 BUILDRESULTS=buildresults/gcc-7' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/gcc-7', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + gcc(id: 'gcc-7', name: 'gcc-7'), + ] + ) + } + } + } + stage('Cross compile for ARM') + { + steps + { + sh 'make CROSS=cortex-m4_hardfloat BUILDRESULTS=buildresults/arm' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/arm', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + gcc(id: 'gcc-arm', name: 'gcc-arm'), + ] + ) + } + } + } + stage('Test') + { + steps + { + sh 'make test' + } + post + { + always + { + junit 'buildresults/test/*.xml' + } + } + } + stage('Complexity') + { + steps + { + sh 'make complexity' + } + } + stage('CppCheck') + { + steps + { + sh 'make cppcheck-xml' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + cppCheck( + pattern: 'buildresults/**/cppcheck.xml', + ), + ] + ) + } + } + } + stage('Clang Tidy') + { + steps + { + sh 'make tidy' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + clangTidy(), + ] + ) + } + } + } + stage('Clang Analyzer') + { + steps + { + sh 'make scan-build' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + clang(id: 'scan-build', name: 'scan-build'), + ] + ) + } + } + } + stage('sloccount') + { + steps + { + sh 'make sloccount-report-full' + } + post + { + success + { + sloccountPublish encoding: '', ignoreBuildFailure: true, pattern: 'buildresults/sloccount_detailed.sc' + } + } + } + stage('Coverage') + { + steps + { + sh 'make coverage' + } + post + { + success + { + cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'buildresults/coverage/coverage-xml.xml', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false + } + } + } + stage('Lint Documentation') + { + steps + { + sh 'make vale' + } + } + stage('Generate Documentation') + { + steps + { + sh 'make docs' + } + } + stage('Generate Release') + { + steps + { + sh 'make package' + } + } + } + post + { + always + { + // Scan for open tasks, warnings, issues, etc. + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + taskScanner( + excludePattern: 'buildresults/**, cmake/**', + includePattern: '**/*.c, **/*.cpp, **/*.h, **/*.hpp, **/*.sh, **/*.build', + normalTags: 'TODO, to do, WIP', + highTags: 'FIXME, FIX', + ignoreCase: true, + ), + ] + ) + } + } +} diff --git a/tools/Jenkinsfile b/tools/Jenkinsfile new file mode 100644 index 0000000..ae29eed --- /dev/null +++ b/tools/Jenkinsfile @@ -0,0 +1,449 @@ +#!groovy +@Library('jenkins-pipeline-lib') _ + +pipeline +{ + agent any + environment + { + GIT_CHANGE_LOG = gitChangeLog(currentBuild.changeSets) + } + parameters + { + string(defaultValue: '0', description: 'Major version number (x.0.0)', name: 'MAJOR_VERSION') + string(defaultValue: '1', description: 'Minor version number (0.x.0)', name: 'MINOR_VERSION') + } + triggers + { + //At 04:00 on every day-of-week from Monday through Friday. + pollSCM('H 4 * * 1-5') + } + stages + { + stage('Setup') + { + steps + { + gitTagPreBuild "${params.MAJOR_VERSION}.${params.MINOR_VERSION}.${BUILD_NUMBER}" + + echo 'Removing existing build results' + sh 'make distclean' + } + } + stage('Build for Clang') + { + steps + { + sh 'make' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + clang(), + ] + ) + } + } + } + stage('Build for GCC-9') + { + steps + { + sh 'make NATIVE=gcc-9 BUILDRESULTS=buildresults/gcc-9' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/gcc-9', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + gcc(id:'gcc-9', name: 'gcc-9'), + ] + ) + } + } + } + stage('Build for GCC-8') + { + steps + { + sh 'make NATIVE=gcc-8 BUILDRESULTS=buildresults/gcc-8' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/gcc-8/', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + gcc(id: 'gcc-8', name: 'gcc-8'), + ] + ) + } + } + } + stage('Build for GCC-7') + { + steps + { + sh 'make NATIVE=gcc-7 BUILDRESULTS=buildresults/gcc-7' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/gcc-7', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + gcc(id: 'gcc-7', name: 'gcc-7'), + ] + ) + } + } + } + stage('Cross compile for ARM') + { + steps + { + sh 'make CROSS=cortex-m4_hardfloat BUILDRESULTS=buildresults/arm' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + sourceDirectory: 'buildresults/arm', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + gcc(id: 'gcc-arm', name: 'gcc-arm'), + ] + ) + } + } + } + stage('Test') + { + steps + { + sh 'make test' + } + post + { + always + { + junit 'buildresults/test/*.xml' + } + } + } + stage('Complexity') + { + steps + { + sh 'make complexity' + } + } + stage('CppCheck') + { + steps + { + sh 'make cppcheck-xml' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + cppCheck( + pattern: 'buildresults/**/cppcheck.xml', + ), + ] + ) + } + } + } + stage('Clang Tidy') + { + steps + { + sh 'make tidy' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + clangTidy(), + ] + ) + } + } + } + stage('Clang Analyzer') + { + steps + { + sh 'make scan-build' + } + post + { + always + { + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/project-skeleton/master', + filters: [ + excludeFile('subprojects/*') + ], + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + clang(id: 'scan-build', name: 'scan-build'), + ] + ) + } + } + } + stage('sloccount') + { + steps + { + sh 'make sloccount-report-full' + } + post + { + success + { + sloccountPublish encoding: '', ignoreBuildFailure: true, pattern: 'buildresults/sloccount_detailed.sc' + } + } + } + stage('Coverage') + { + steps + { + sh 'make coverage' + } + post + { + success + { + cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'buildresults/coverage/coverage-xml.xml', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false + } + } + } + stage('Lint Documentation') + { + steps + { + sh 'make vale' + } + } + stage('Generate Documentation') + { + steps + { + sh 'make docs' + } + } + stage('Generate Release') + { + steps + { + sh 'make package' + } + } + stage('Archive') + { + steps + { + dir('buildresults/releases') + { + archiveArtifacts '*.tgz' + } + } + } + } + post + { + always + { + // Scan for open tasks, warnings, issues, etc. + recordIssues( + healthy: 5, + unhealthy: 10, + aggregatingResults: true, + referenceJobName: 'ea-nightly/cmake-project-skeleton/master', + qualityGates: [ + // 3 new issue: unstable + [threshold: 3, type: 'DELTA', unstable: true], + // 5 new issues: failed build + [threshold: 5, type: 'DELTA', unstable: false], + // 10 total issues: unstable + [threshold: 10, type: 'TOTAL', unstable: true], + // 20 total issues: fail + [threshold: 20, type: 'TOTAL', unstable: false] + ], + tools: [ + taskScanner( + excludePattern: 'buildresults/**, cmake/**', + includePattern: '**/*.c, **/*.cpp, **/*.h, **/*.hpp, **/*.sh, **/*.build', + normalTags: 'TODO, to do, WIP', + highTags: 'FIXME, FIX', + ignoreCase: true, + ), + ] + ) + + gitTagCleanup "${params.MAJOR_VERSION}.${params.MINOR_VERSION}.${BUILD_NUMBER}" + } + success + { + gitTagSuccess "${params.MAJOR_VERSION}.${params.MINOR_VERSION}.${BUILD_NUMBER}" + } + failure + { + /* + * This job does not have a GitHub configuration, + * so we need to create a dummy config + */ + githubSetConfig('69e4682e-2951-492f-b828-da06364c322d') + githubFileIssue() + emailNotify(currentBuild.currentResult) + } + } +} diff --git a/tools/deploy_skeleton.sh b/tools/deploy_skeleton.sh new file mode 100755 index 0000000..74258eb --- /dev/null +++ b/tools/deploy_skeleton.sh @@ -0,0 +1,170 @@ +#!/bin/bash + +USE_GIT=1 +USE_SUBMODULES=1 +USE_ADR=0 +USE_POTTERY=0 +COPY_LICENSE=0 +REPLACE_NAME= +CORE_FILES="docs src test tools .clang-format .clang-tidy BuildOptions.cmake CMakeLists.txt Makefile Packaging.cmake README.md" +GIT_FILES=".gitattributes .github .gitignore" +SUBMODULE_DIRS=("cmake") +SUBMODULE_URLS=("https://github.com/embeddedartistry/cmake-buildsystem.git") + +# Detect sed -i command b/c OS X uses BSD sed +if [ "$(uname)" == "Darwin" ]; then + SED="sed -i ''" +else + SED="sed -i" +fi + +# Parse optional arguments +while getopts aplghsr: opt; do + case $opt in + a) USE_ADR=1 + ;; + p) USE_POTTERY=1 + ;; + l) COPY_LICENSE=1 + ;; + g) USE_GIT=0 + USE_SUBMODULES=0 + ;; + s) USE_SUBMODULES=0 + ;; + r) REPLACE_NAME="$OPTARG" + ;; + h) # Help + echo "Usage: deploy_skeleton.sh [optional ags] dest_dir" + echo "Optional args:" + echo " -a: initialize destination to use adr-tools" + echo " -p: initialize destination to use pottery" + echo " -l: copy the license file" + echo " -g: Assume non-git environment. Installs submodule files directly." + echo " -s: Don't use submodules, and copy files directly" + echo " -r : Replace template project/app name values with specified name" + exit 0 + ;; + \?) echo "Invalid option -$OPTARG" >&2 + ;; + esac +done + +# Shift off the getopts args, leaving us with positional args +shift $((OPTIND -1)) + +# First positional argument is the destination folder that skeleton files will be installed to +DEST_DIR=$1 +STARTING_DIR=$PWD + +# Check to see if we're in tools/ or the project-skeleton root +CHECK_DIR=cmake +if [ ! -d "$CHECK_DIR" ]; then + cd .. + if [ ! -d "$CHECK_DIR" ]; then + echo "This script must be run from the project skeleton root or the tools/ directory." + exit 1 + fi +fi + +# Adjust the destination directory for relative paths in case we changed directories +# This method still supports absolute directory paths for the destination +if [ ! -d "$DEST_DIR" ]; then + if [ -d "$STARTING_DIR/$DEST_DIR" ]; then + DEST_DIR=$STARTING_DIR/$DEST_DIR + else + echo "Destination directory cannot be found. Does it exist?" + exit 1 + fi +fi + +# Copy core skeleton files to the destination +cp -r $CORE_FILES $DEST_DIR + +# Delete the deploy skeleton script from the destination +rm $DEST_DIR/tools/deploy_skeleton.sh $DEST_DIR/tools/download_and_deploy.sh + +# Copy git files to the destination +if [ $USE_GIT == 1 ]; then + cp -r $GIT_FILES $DEST_DIR +fi + +# Manually copy submodule files +if [ $USE_SUBMODULES == 0 ]; then + git submodule update --init --recursive + cp -r ${SUBMODULE_DIRS[@]} $DEST_DIR +fi + +if [ $COPY_LICENSE == 1 ]; then + cp LICENSE $DEST_DIR +fi + +## The following operations all take place in the destination directory +cd $DEST_DIR + +# Initialize Submodules +if [ $USE_SUBMODULES == 1 ]; then + cd $DEST_DIR + for index in ${!SUBMODULE_URLS[@]}; do + git submodule add ${SUBMODULE_URLS[$index]} ${SUBMODULE_DIRS[$index]} + done + git commit -m "Add submodules from project skeleton." +else + find ${SUBMODULE_DIRS[@]} -name ".git*" -exec rm -rf {} \; +fi + +# Commit Files +if [ $USE_GIT == 1 ]; then + git add --all + git commit -m "Initial commit of project skeleton files." +fi + +# Replace placeholder names +if [[ ! -z $REPLACE_NAME ]]; then + # Convert spaces to underscores before replacing names + REPLACE_NAME=${REPLACE_NAME// /_} + eval $SED "s/MYPROJECT/$REPLACE_NAME/g" "CMakeLists.txt" + eval $SED "s/MYPROJECT/$REPLACE_NAME/g" "test/CMakeLists.txt" + # Convert to all upper case for variable name + # We use awk beacuse it properly handles UTF-8/multibyte input + REPLACE_NAME=$(echo "$REPLACE_NAME" | awk '{print toupper($0)}') + eval $SED "s/PROJECTVARNAME/$REPLACE_NAME/g" "CMakeLists.txt" + eval $SED "s/PROJECTVARNAME/$REPLACE_NAME/g" "test/CMakeLists.txt" + eval $SED "s/PROJECTVARNAME/$REPLACE_NAME/g" "BuildOptions.cmake" + if [ $USE_GIT == 1 ]; then + git commit -am "Replace placeholder values in build files with $REPLACE_NAME." + fi +fi + +# Initialize adr-tools +if [ $USE_ADR == 1 ]; then + adr init docs/ + if [ $USE_GIT == 1 ]; then + git add --all + git commit -m "Initialize adr-tools." + fi +fi + +# Initialize pottery +if [ $USE_POTTERY == 1 ]; then + pottery init + pottery note "Initial creation of project repository" + if [ $USE_GIT == 1 ]; then + git add --all + git commit -m "Initialize pottery and document repository creation." + fi +fi + +# Push all changes to the server +if [ $USE_GIT == 1 ]; then + git push || echo "WARNING: git push failed: check repository." +fi + +if [[ $COPY_LICENSE == 0 && ! -f "LICENSE" || ! -f "LICENSE.md" ]]; then + echo "NOTE: Your project does not have a LICENSE or LICENSE.md file in the project root." +fi + +if [[ -z $REPLACE_NAME ]]; then + echo "NOTE: Replace the placeholder project name values in CMakeLists.txt and test/CMakeLists.txt (MYPROJECT)" + echo "NOTE: Replace the placeholder project variable values in CMakeLists.txt, test/CMakeLists.txt, and BuildOptions.cmake (PROJECTVARNAME)" +fi diff --git a/tools/download_and_deploy.sh b/tools/download_and_deploy.sh new file mode 100755 index 0000000..8b1d9d1 --- /dev/null +++ b/tools/download_and_deploy.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# This script forwards all arguments to the deploy_skeleton.sh script +# The directory supplied to the script *must* be an absolute path! + +cd /tmp +git clone git@github.com:embeddedartistry/cmake-project-skeleton.git --recursive --depth 1 +cd project-skeleton +bash tools/deploy_skeleton.sh $@ +cd ../ +rm -rf project-skeleton diff --git a/tools/install_arm_gcc.sh b/tools/install_arm_gcc.sh new file mode 100755 index 0000000..4b628d7 --- /dev/null +++ b/tools/install_arm_gcc.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# +# You can override the installation path for toolchains by defining TOOLCHAIN_INSTALL_DIR +# If the toolchain directory do not require sudo permissions, disable the use +# of sudo by defining TOOLCHAIN_DISABLE_SUDO=1 + +TOOLCHAIN_INSTALL_DIR=${TOOLCHAIN_INSTALL_DIR:-/usr/local/toolchains} +TOOLCHAIN_DISABLE_SUDO=${TOOLCHAIN_DISABLE_SUDO:-0} + +TOOLCHAIN_SUDO=sudo +if [ $TOOLCHAIN_DISABLE_SUDO == 1 ]; then + + TOOLCHAIN_SUDO= +fi + +OSX_ARM_URL="https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-mac.tar.bz2" +LINUX_ARM_URL="https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-aarch64-linux.tar.bz2" + +if [ "$(uname)" == "Darwin" ]; then + ARM_URL=$OSX_ARM_URL + ARM_DIR=$(basename "$ARM_URL" -mac.tar.bz2) +else + ARM_URL=$LINUX_ARM_URL + ARM_DIR=$(basename "$ARM_URL" -aarch64-linux.tar.bz2) +fi + +ARM_ARCHIVE=$(basename "$ARM_URL") + +################################### +# Download and install dependency # +################################### + +cd /tmp +wget $ARM_URL +${TOOLCHAIN_SUDO} mkdir -p ${TOOLCHAIN_INSTALL_DIR} +# Move current toolchain if it exists +if [ -d "${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi" ]; then + ${TOOLCHAIN_SUDO} rm -rf ${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi-bak + ${TOOLCHAIN_SUDO} mv ${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi ${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi-bak +fi +${TOOLCHAIN_SUDO} tar xf ${ARM_ARCHIVE} --directory ${TOOLCHAIN_INSTALL_DIR} +${TOOLCHAIN_SUDO} mv ${TOOLCHAIN_INSTALL_DIR}/${ARM_DIR} ${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi +rm ${ARM_ARCHIVE} diff --git a/tools/install_deps.sh b/tools/install_deps.sh new file mode 100755 index 0000000..30933da --- /dev/null +++ b/tools/install_deps.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +STARTING_DIR=$PWD +UPDATE=0 +PIP_UPDATE= +BREW_COMMAND="install" +APT_COMMAND="install" +UPDATE_ENV=0 +TOOLCHAIN_INSTALL_DIR=${TOOLCHAIN_INSTALL_DIR:-/usr/local/toolchains} +TOOL_INSTALL_DIR=${TOOL_INSTALL_DIR:-/usr/local/tools} +TOOLCHAIN_DISABLE_SUDO=${TOOLCHAIN_DISABLE_SUDO:-0} +TOOL_DISABLE_SUDO=${TOOL_DISABLE_SUDO:-0} +TOOLS_SUDO=sudo + +if [ $TOOL_DISABLE_SUDO == 1 ]; then + TOOLS_SUDO= +fi + +# Packages to Install +BREW_PACKAGES=("python3" "ninja" "wget" "gcc@7" "gcc@8" "gcc@9" "llvm" "adr-tools" "cmocka" "pkg-config") +BREW_PACKAGES+=("vale" "doxygen" "cppcheck" "clang-format" "gcovr" "lcov" "sloccount" "cmake") +APT_PACKAGES=("python3" "python3-pip" "ninja-build" "wget" "build-essential" "clang" "lld" "llvm") +APT_PACKAGES+=("clang-tools" "libcmocka0" "libcmocka-dev" "pkg-config" "sloccount" "curl") +APT_PACKAGES+=("doxygen" "cppcheck" "gcovr" "lcov" "clang-format" "clang-tidy" "clang-tools") +APT_PACKAGES+=("gcc-7" "g++-7" "gcc-8" "g++-8" "gcc-9" "g++-9") +PIP3_PACKAGES=("lizard") + +while getopts "euh" opt; do + case $opt in + e) UPDATE_ENV=1 + ;; + u) UPDATE=1 + PIP_UPDATE="--upgrade" + BREW_COMMAND="upgrade" + APT_COMMAND="upgrade" + ;; + h) # Help + echo "Usage: install_deps.sh [optional ags]" + echo "Optional args:" + echo " -u: Run an update instead of install" + echo " -e: Include environment setup during install process (.bashrc + .bash_profile)" + exit 0 + ;; + \?) echo "Invalid option -$OPTARG" >&2 + ;; + esac +done + +if [ "$(uname)" == "Darwin" ]; then + # OS X case + ARM_URL=$OSX_ARM_URL + ARM_DIR=$(basename "$ARM_URL" -mac.tar.bz2) + + if [ $UPDATE == 1 ]; then + # update homebrew + brew update + else + #install brew if unavailable + if [ -z "$(command -v brew)" ]; then + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + fi + + brew tap homebrew/cask-versions + fi + + brew ${BREW_COMMAND} ${BREW_PACKAGES[@]} + pip3 install ${PIP3_PACKAGES[@]} ${PIP_UPDATE} +else + # WSL/Linux Case + ARM_URL=$LINUX_ARM_URL + ARM_DIR=$(basename "$ARM_URL" -aarch64-linux.tar.bz2) + + sudo apt-get update + sudo apt ${APT_COMMAND} -y ${APT_PACKAGES[@]} + sudo -H pip3 install ${PIP3_PACKAGES[@]} ${PIP_UPDATE} + + cd /tmp + wget https://install.goreleaser.com/github.com/ValeLint/vale.sh + sudo sh vale.sh -b /usr/local/bin + rm vale.sh + + # Install adr-tools + if [ $UPDATE == 1 ]; then + cd /usr/local/tools/adr-tools + ${TOOLS_SUDO} git pull + else + ${TOOLS_SUDO} mkdir -p /usr/local/tools + cd /usr/local/tools + ${TOOLS_SUDO} git clone https://github.com/npryce/adr-tools.git --recursive + fi +fi + +########################### +# Common Dependency Steps # +########################### + +# Install gcc-arm-none-eabi +if [ $UPDATE == 0 ]; then + # Assume that the two scripts are contained in the same directory + cd $STARTING_DIR + source $(dirname $0)/install_arm_gcc.sh +fi + +if [ $UPDATE == 1 ]; then + # Update Pottery + cd ${TOOL_INSTALL_DIR}/pottery + ${TOOLS_SUDO} git pull +else + ${TOOLS_SUDO} mkdir -p ${TOOL_INSTALL_DIR}/tools + cd /usr/local/tools + ${TOOLS_SUDO} git clone https://github.com/npryce/pottery.git --recursive +fi + +############################# +# Configure the Environment # +############################# + +if [ $UPDATE == 0 ]; then + if [ $UPDATE_ENV == 1 ]; then + # Assume that the two scripts are contained in the same directory + cd $STARTING_DIR + source $(dirname $0)/setup_env.sh + else + echo "You may need to manually modify your PATH to reference the programs in $TOOLCHAIN_INSTALL_DIR and $TOOL_INSTALL_DIR" + fi +fi diff --git a/tools/setup_env.sh b/tools/setup_env.sh new file mode 100755 index 0000000..bf9862a --- /dev/null +++ b/tools/setup_env.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +TOOLCHAIN_INSTALL_DIR=${TOOLCHAIN_INSTALL_DIR:-/usr/local/toolchains} +TOOL_INSTALL_DIR=${TOOL_INSTALL_DIR:-/usr/local/tools} + +# For OS X, we need .bash_profile to invoke `.bashrc`. +# Append to file in case it already exists +if [ "$(uname)" == "Darwin" ]; then +cat << ENDOFBLOCK >> $HOME/.bash_profile +if [ -f \$HOME/.bashrc ]; then + source \$HOME/.bashrc +fi +ENDOFBLOCK +fi + +PATHMOD="$TOOLCHAIN_INSTALL_DIR/gcc-arm-none-eabi/bin:$TOOL_INSTALL_DIR/pottery/src" +if [ "$(uname)" == "Darwin" ]; then + PATHMOD="$PATHMOD:/usr/local/opt/llvm/bin" +else + PATHMOD="$PATHMOD:$TOOL_INSTALL_DIR:adr-tools/src" +fi + + +cat << ENDOFBLOCK >> $HOME/.bashrc +################ +# Path Updates # +################ + +export PATH="$PATHMOD:\$PATH" +# set PATH so it includes user's private bin if it exists +if [ -d "\$HOME/bin" ] ; then + PATH="\$HOME/bin:\$PATH" +fi +ENDOFBLOCK + +cat << ENDOFBLOCK >> $HOME/.bashrc +######################### +# Aliases and Functions # +######################### +function deploy_skeleton() +{ + INITIAL_DIR=\$(pwd) + cd /tmp + wget https://gist.githubusercontent.com/phillipjohnston/bb95f19d156007f99be4c10c1efdf694/raw/f2f141e31fca0a12eb391e8251efe2ce1f9e68bd/download_and_deploy.sh + bash download_and_deploy.sh \$@ + rm download_and_deploy.sh + cd \$INITIAL_DIR +} +alias init_skeleton='deploy_skeleton -a -p `pwd`' +function init_repo() +{ + URL=\$1 + shift + git clone \$URL + cd \$(basename "\$URL" .git) + deploy_skeleton -a -p \${@} `pwd` +} + +# Skeleton Update Aliases +alias sm_update_build="cd build; git checkout master; git pull; cd ../" +alias sm_update_commit_build="cd build; git checkout master; git pull; cd ../; git add build; git commit -m 'Update build submodule to master'" +ENDOFBLOCK From 754268c293f2a6b804386ad806627485cc28d9ea Mon Sep 17 00:00:00 2001 From: Fin Orr Date: Sat, 17 Feb 2024 18:50:41 +0700 Subject: [PATCH 3/4] Easier to quickly understand repo purpose --- README.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 51d3a9e..bbf8217 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,15 @@ ## Overview -**PolyFit** is a C library designed to facilitate accurate polynomial fitting for curve approximation, allowing for interpolation and extrapolation of data points. With just a few input datapoints, you can model your system quickly and efficiently. +**PolyFit** is a C library designed to facilitate accurate polynomial fitting for curve approximation, allowing for interpolation and extrapolation of data. With just a few input datapoints, you can model your system quickly and efficiently. + +## Features + +- Polynomial fitting for curve approximation. + +- Interpolation and extrapolation functionality for predicting additional data points. + +- Lightweight and easy-to-integrate into existing C projects. ## Table of Contents @@ -60,16 +68,6 @@ Sound a bit asbtract? No worries, here's some examples of where PolyFit can help **[Back to top](#table-of-contents)** -## Features - -- Polynomial fitting for curve approximation. - -- Interpolation and extrapolation functionality for predicting additional data points. - -- Lightweight and easy-to-integrate into existing C projects. - -**[Back to top](#table-of-contents)** - # Project Status The current system requires the user to specify the desired order of polynomial to be fit to the data. From f65667f2418e7f56cc992a3eb791012b4aedf43f Mon Sep 17 00:00:00 2001 From: Fin Orr Date: Sat, 2 May 2026 23:58:41 +0200 Subject: [PATCH 4/4] feat: refactor, bug fixes, unit tests --- .clang-format | 289 --------- .clang-tidy | 90 --- .gitattributes | 12 - .github/ISSUE_TEMPLATE.md | 32 - .github/ISSUE_TEMPLATE/FEATURE.md | 27 - .github/ISSUE_TEMPLATE/ISSUE.md | 48 -- .github/ISSUE_TEMPLATE/QUESTION.md | 15 - .github/ISSUE_TEMPLATE/config.yml | 1 - .github/PULL_REQUEST_TEMPLATE.md | 21 - .github/PULL_REQUEST_TEMPLATE/ccc.md | 49 -- .../pull_request_template.md | 42 -- .github/workflows/ci.yml | 36 + .gitignore | 68 +- .gitmodules | 3 - BuildOptions.cmake | 121 ---- CMakeLists.txt | 111 +--- docs/CONTRIBUTING.md => CONTRIBUTING.md | 2 +- LICENSE | 222 +------ Makefile | 203 ------ Packaging.cmake | 30 - README.md | 307 +++------ docs/CODE_OF_CONDUCT.md | 5 - polyfit.c | 614 ++++++++++++++++++ polyfit.h | 306 +++++++++ src/CMakeLists.txt | 3 - src/app/CMakeLists.txt | 10 - src/app/demo.c | 90 --- src/lib/CMakeLists.txt | 26 - src/lib/polyfit/CMakeLists.txt | 2 - src/lib/polyfit/polyfit.c | 269 -------- src/lib/polyfit/polyfit.h | 91 --- src/utility/CMakeLists.txt | 15 - test/CMakeLists.txt | 32 - test/README.md | 1 - tests/CMakeLists.txt | 17 + tests/test_polyfit.cpp | 508 +++++++++++++++ tools/CI.jenkinsfile | 427 ------------ tools/Jenkinsfile | 449 ------------- tools/deploy_skeleton.sh | 170 ----- tools/download_and_deploy.sh | 10 - tools/install_arm_gcc.sh | 43 -- tools/install_deps.sh | 126 ---- tools/setup_env.sh | 62 -- 43 files changed, 1650 insertions(+), 3355 deletions(-) delete mode 100644 .clang-format delete mode 100644 .clang-tidy delete mode 100644 .gitattributes delete mode 100644 .github/ISSUE_TEMPLATE.md delete mode 100644 .github/ISSUE_TEMPLATE/FEATURE.md delete mode 100644 .github/ISSUE_TEMPLATE/ISSUE.md delete mode 100644 .github/ISSUE_TEMPLATE/QUESTION.md delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md delete mode 100644 .github/PULL_REQUEST_TEMPLATE/ccc.md delete mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md create mode 100644 .github/workflows/ci.yml delete mode 100644 .gitmodules delete mode 100644 BuildOptions.cmake rename docs/CONTRIBUTING.md => CONTRIBUTING.md (95%) delete mode 100644 Makefile delete mode 100644 Packaging.cmake delete mode 100644 docs/CODE_OF_CONDUCT.md create mode 100644 polyfit.c create mode 100644 polyfit.h delete mode 100644 src/CMakeLists.txt delete mode 100644 src/app/CMakeLists.txt delete mode 100644 src/app/demo.c delete mode 100644 src/lib/CMakeLists.txt delete mode 100644 src/lib/polyfit/CMakeLists.txt delete mode 100644 src/lib/polyfit/polyfit.c delete mode 100644 src/lib/polyfit/polyfit.h delete mode 100644 src/utility/CMakeLists.txt delete mode 100644 test/CMakeLists.txt delete mode 100644 test/README.md create mode 100644 tests/CMakeLists.txt create mode 100644 tests/test_polyfit.cpp delete mode 100644 tools/CI.jenkinsfile delete mode 100644 tools/Jenkinsfile delete mode 100755 tools/deploy_skeleton.sh delete mode 100755 tools/download_and_deploy.sh delete mode 100755 tools/install_arm_gcc.sh delete mode 100755 tools/install_deps.sh delete mode 100755 tools/setup_env.sh diff --git a/.clang-format b/.clang-format deleted file mode 100644 index f98657b..0000000 --- a/.clang-format +++ /dev/null @@ -1,289 +0,0 @@ ---- -# Updated for clang-format 12.0.1, some commented values are there -# for when we update to clang-format 13 -Language: Cpp -Standard: Latest #Cpp20 -# BasedOnStyle: LLVM -# The extra indent or outdent of access modifiers (e.g., public) -AccessModifierOffset: -2 -# Align parameters on the open bracket -# someLongFunction(argument1, -# argument2); -AlignAfterOpenBracket: Align -# Align array column and right justify the columns -#AlignArayOfStructures: Right -# Do not align equals signs of consecutive assignments -AlignConsecutiveAssignments: None -# Do not align the value of consecutive macros -AlignConsecutiveMacros: None -# Do not align the colons of consecutive bitfields -AlignConsecutiveBitFields: None -# Do not align the variable names of consecutive declarations -AlignConsecutiveDeclarations: None -# Align escaped newlines in macros - as far left as possible -AlignEscapedNewlinesLeft: Left -# Horizontally align operands of binary and ternary expressions -# Keeping the operand on the right edge of the upper line -AlignOperands: Align -# Do not align consecutive comments that follow a line of code -AlignTrailingComments: false -# If a function call or braced initializer list doesn’t fit on a line, -# allow putting all arguments onto the next line, even if BinPackArguments is false. -AllowAllArgumentsOnNextLine: true -# If a constructor definition with a member initializer list doesn’t fit on a -# single line, allow putting all member initializers onto the next line, if -# `ConstructorInitializerAllOnOneLineOrOnePerLine` is true. Note that this parameter -# has no effect if `ConstructorInitializerAllOnOneLineOrOnePerLine` is false. -AllowAllConstructorInitializersOnNextLine: true -# If the function declaration doesn’t fit on a line, allow putting all -# parameters of a function declaration onto the next line even if BinPackParameters is false. -AllowAllParametersOfDeclarationOnNextLine: true -# Short blocks (e.g., empty while loop, or a for loop that just continues) are -# never merged into a single line -AllowShortBlocksOnASingleLine: Never -# Short case labels are not contracted into a single line -AllowShortCaseLabelsOnASingleLine: false -# Short enums are not contracted into a single line -AllowShortEnumsOnASingleLine: false -# Short functions are not contracted into a single line -AllowShortFunctionsOnASingleLine: None -# Short If Statements are not contracted into a single line -AllowShortIfStatementsOnASingleLine: Never -# Short lambdas are not contracted into a single line -AllowShortLambdasOnASingleLine: None -# short loops are not contracted to a single line -AllowShortLoopsOnASingleLine: false -# Do not break after the return type -AlwaysBreakAfterReturnType: None -# do not always break before multiline string literals -AlwaysBreakBeforeMultilineStrings: false -# Always break after a template declaration -AlwaysBreakTemplateDeclarations: Yes -# A vector of strings that should be interpreted as attributes/qualifiers instead of identifiers. -# This can be useful for language extensions or static analyzer annotations -AttributeMacros: ['__capability', '__unused'] -# Function call arguments do not always have to have their own line if they don't -# fit on one line -BinPackArguments: true -# Function parameters do not always have to have their own line if they don't -# fit on one line -BinPackParameters: true -# Add one space on each side of the : -BitFieldColonSpacing: Both -# Configure each individual brace in BraceWrapping. -BreakBeforeBraces: Custom -BraceWrapping: - # Opening brace under case label - AfterCaseLabel: true - # Class brace opens on the same line as the class name - AfterClass: true - # Braces are under control statement - AfterControlStatement: Always - # Braces are under enum - AfterEnum: true - # Braces are under function prototype - AfterFunction: true - # Braces are under namespace - AfterNamespace: true - # Braces are under struct keyword - AfterStruct: true - # Braces are under union keyword - AfterUnion: true - # Braces are under extern keyword - AfterExternBlock: true - # Braces are under catch keyword - BeforeCatch: true - # else keyword is placed under if close brace - BeforeElse: true - # Do not place a trailing while loop below the close brace - BeforeWhile: false - # Do not indent wrapped braces - IndentBraces: false - # Empty function body braces are on multiple lines - SplitEmptyFunction: true - # Empty class/struct/union body braces are on multiple lines - SplitEmptyRecord: true - # empty namespace body braces are on multiple lines - SplitEmptyNamespace: true -# For splitting long binary operations, break after the operator -BreakBeforeBinaryOperators: None -# Place concept declaration on a new line -BreakBeforeConceptDeclarations: true -# Break after the ternary operator - ? -BreakBeforeTernaryOperators: false -# Break constructor initializers after the colon and commas -BreakConstructorInitializers: AfterColon -# Break inheritance list after the colon and comma -BreakInheritanceList: AfterColon -# Allow breaking long string literals into multiple lines -BreakStringLiterals: true -# Max Width of a line when formatting -ColumnLimit: 100 -# A regular expression that describes comments with special meaning, -# which should not be split into lines or otherwise changed. -CommentPragmas: '^ IWYU pragma:' -# Each namespace declaration is placed on a new line -CompactNamespaces: false -# Do not require initializers to be on their own lines when breaking -ConstructorInitializerAllOnOneLineOrOnePerLine: false -# The number of characters to use for indentation of constructor initializer -# lists as well as inheritance lists. -ConstructorInitializerIndentWidth: 4 -# Indent width for line continuations. -ContinuationIndentWidth: 4 -# format braced lists as best suited for C++11 braced lists -Cpp11BracedListStyle: true -# Analyze the formatted file for the most used line ending (\r\n or \n). -# UseCRLF is only used as a fallback if none can be derived. -DeriveLineEnding: true -# Do not read the file to derive pointer alignment requirements. Uses PointerAlignment value. -DerivePointerAlignment: false -# Do not completely disable formatting -DisableFormat: false -# Remove all empty lines after access modifiers -#EmptyLineAfterAccessModifier: Never -# Add empty line only when access modifier starts a new logical block. -# Logical block is a group of one or more member fields or functions. -EmptyLineBeforeAccessModifier: LogicalBlock -# add missing namespace end comments for short namespaces and fixes invalid existing ones. -FixNamespaceComments: true -# A vector of macros that should be interpreted as foreach loops instead of as function calls. -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -# Sort each #include block separately (blocks of includes are separated by empty lines) -IncludeBlocks: Preserve -# Regular expressions denoting the different #include categories used for ordering #includes. -IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - SortPriority: 0 - CaseSensitive: false - - Regex: '^(<|"(gtest|gmock|isl|json|catch2|cmocka)/)' - Priority: 3 - SortPriority: 0 - CaseSensitive: false - - Regex: '.*' - Priority: 1 - SortPriority: 0 - CaseSensitive: false -# Specify a regular expression of suffixes that are allowed in the file-to-main-include mapping. -# use this regex of allowed suffixes to the header stem. -# A partial match is done, so that: - “” means “arbitrary suffix” - “$” means “no suffix” -IncludeIsMainRegex: '$' -# Specify a regular expression for files being formatted that are allowed to be considered -# “main” in the file-to-main-include mapping. -IncludeIsMainSourceRegex: '' -# access modifiers are indented (or outdented) relative to the record members, -# respecting the AccessModifierOffset -#IndentAccessModifiers: false -# Do not indent case blocks one level from case label -IndentCaseBlocks: false -# Do indent case labels within a switch block -IndentCaseLabels: true -# Use AfterExternBlock's indenting rule -IndentExternBlock: AfterExternBlock -# Goto labels are indented to proper level -IndentGotoLabels: true -# Indents preprocessor directives before the hash. -IndentPPDirectives: BeforeHash -# Indent requires clause in a template -IndentRequires: true -# Number of coluns to use for indentation -IndentWidth: 4 -# Indent if a function definition or declaration is wrapped after the type. -IndentWrappedFunctionNames: true -# Remove empty lines at the start of a block -KeepEmptyLinesAtTheStartOfBlocks: false -# Align lambda body relative to the start of the lambda signature -#LambdaBodyIndentation: Signature -# A regular expression matching macros that start a block. -MacroBlockBegin: '' -# A regular expression matching macros that end a block. -MacroBlockEnd: '' -# Maximum number of consecutive empty lines to keep -MaxEmptyLinesToKeep: 1 -# Don’t indent namespaces -NamespaceIndentation: None -# A vector of macros which are used to open namespace blocks -#NamespaceMacros: '' -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -# align pointers: int* ptr -PointerAlignment: Left -# align references like pointers -#ReferenceAlignment: Pointer -# Clang-format will attempt to reflow long comments -ReflowComments: true -# Always have an ending namespace commment -#ShortNamespaceLines: 0 -# Include sorting is alphabetical and case insensitive -SortIncludes: false #CaseInsensitive -# using declarations will be alphabetically sorted -SortUsingDeclarations: true -# Do not insert a space after a C-style cast -SpaceAfterCStyleCast: false -# Do not insert as pace after a logical not (!) -SpaceAfterLogicalNot: false -# Do not insert as pace after the template keyword -SpaceAfterTemplateKeyword: false -# Don't ensure spaces around pointer qualifiers, use PointerAlignment instead -SpaceAroundPointerQualifiers: Default -# Place spaces before assignment operators (=, +=, etc.) -SpaceBeforeAssignmentOperators: true -# Do not place a space befrore a case statement colon -SpaceBeforeCaseColon: false -# Do not place a space befrore a C++11 braced list -SpaceBeforeCpp11BracedList: false -# Do place a space between the constructor and the initializer colon -SpaceBeforeCtorInitializerColon: true -# Place a space between the class and the inheritance colon -SpaceBeforeInheritanceColon: true -# Never place a space between an item and following parens -SpaceBeforeParens: Never -# do not place a space before a range based for loop -SpaceBeforeRangeBasedForLoopColon: false -# do not place a space before square brackets [] -SpaceBeforeSquareBrackets: false -# do not place a space in an empty block -SpaceInEmptyBlock: false -# Do not place a space in empty parens -SpaceInEmptyParentheses: false -# Spaces between end of the code and the start of a // line comment -SpacesBeforeTrailingComments: 1 -# Remove spaces within <> : -SpacesInAngles: false #Never -# Do not add spaces in C-style cast parens -SpacesInCStyleCastParentheses: false -# Do not add spaces around if/for/while/switch conditions -SpacesInConditionalStatement: false -# Do not insert spaces inside container literals -SpacesInContainerLiterals: false -# Do not insert spaces after ( and before ) -SpacesInParentheses: false -# Do not insert spaces after [ and before ] -SpacesInSquareBrackets: false -# Macros which are ignored in front of a statement, as if they were an attribute. -# StatementAttributeLikeMacros: -# A vector of macros that should be interpreted as complete statements. -# StatementMacros: '' -# The number of columns used for tab stops. -TabWidth: 4 -# A vector of macros that should be interpreted as type declarations instead of as function calls. -#TypenameMacros: '' -# use \n for line breaks -UseCRLF: false -# Use tabs whenever we need to fill whitespace that spans at least from one tab stop to the next one. -UseTab: Always -# A vector of macros which are whitespace-sensitive and should not be touched. -WhitespaceSensitiveMacros: - - STRINGIZE - - PP_STRINGIZE - - BOOST_PP_STRINGIZE - - NS_SWIFT_NAME - - CF_SWIFT_NAME -... diff --git a/.clang-tidy b/.clang-tidy deleted file mode 100644 index 754e259..0000000 --- a/.clang-tidy +++ /dev/null @@ -1,90 +0,0 @@ ---- -Language: Cpp -# BasedOnStyle: LLVM -AccessModifierOffset: -2 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlinesLeft: true -AlignOperands: true -AlignTrailingComments: false -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: false -AllowShortIfStatementsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Empty -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: true -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterClass: true - AfterControlStatement: true - AfterEnum: true - AfterFunction: true - AfterNamespace: true - AfterObjCDeclaration: false - AfterStruct: true - AfterUnion: true - BeforeCatch: true - BeforeElse: true - IndentBraces: false -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Custom -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true -ColumnLimit: 100 -CommentPragmas: '^ IWYU pragma:' -ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - - Regex: '^(<|"(gtest|isl|json)/)' - Priority: 3 - - Regex: '.*' - Priority: 1 -IncludeIsMainRegex: '$' -IndentCaseLabels: true -IndentWidth: 4 -IndentWrappedFunctionNames: true -JavaScriptQuotes: Leave -KeepEmptyLinesAtTheStartOfBlocks: false -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: Inner -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Left -ReflowComments: true -SortIncludes: true -SpaceAfterCStyleCast: false -SpaceAfterTemplateKeyword: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: Never -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInContainerLiterals: false -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Cpp11 -TabWidth: 4 -UseTab: Always -... diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index a16f581..0000000 --- a/.gitattributes +++ /dev/null @@ -1,12 +0,0 @@ -*.pdf filter=lfs diff=lfs merge=lfs -text -*.jpg filter=lfs diff=lfs merge=lfs -text -*.png filter=lfs diff=lfs merge=lfs -text -*.xlsx filter=lfs diff=lfs merge=lfs -text -*.docx filter=lfs diff=lfs merge=lfs -text -*.zip filter=lfs diff=lfs merge=lfs -text -*.tar filter=lfs diff=lfs merge=lfs -text -*.tgz filter=lfs diff=lfs merge=lfs -text -*.bz2 filter=lfs diff=lfs merge=lfs -text -*.out filter=lfs diff=lfs merge=lfs -text -*.hex filter=lfs diff=lfs merge=lfs -text -*.bin filter=lfs diff=lfs merge=lfs -text diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 796ad28..0000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,32 +0,0 @@ -# Expected Behavior - -Please describe the behavior you are expecting - -# Current Behavior - -What is the current behavior? - -# Failure Information (for bugs) - -Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template. - -## Steps to Reproduce - -Please provide detailed steps for reproducing the issue. - -1. step 1 -2. step 2 -3. you get it... - -## Context - -Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions. - -* Firmware Version: -* Operating System: -* SDK version: -* Toolchain version: - -## Failure Logs - -Please include any relevant log snippets or files here. diff --git a/.github/ISSUE_TEMPLATE/FEATURE.md b/.github/ISSUE_TEMPLATE/FEATURE.md deleted file mode 100644 index 253f605..0000000 --- a/.github/ISSUE_TEMPLATE/FEATURE.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Feature Request -about: Use this template for requesting new features -title: "[FEATURE NAME]" -labels: enhancement -assignees: finorr ---- - -## Expected Behavior - -Please describe the behavior you are expecting - -## Current Behavior - -What is the current behavior? - -## Sample Code - -If applicable, provide a sample code snippet that demonstrates the gist of feature you're proposing. This can be either from a usage standpoint, or an implementation standpoint. - -## Context - -Please provide any relevant information about your setup, which will help us ensure the requested support will work for you. - -* Project Version: -* Operating System: -* Toolchain version: diff --git a/.github/ISSUE_TEMPLATE/ISSUE.md b/.github/ISSUE_TEMPLATE/ISSUE.md deleted file mode 100644 index a787f37..0000000 --- a/.github/ISSUE_TEMPLATE/ISSUE.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: Issue Report -about: Use this template to report a problem -title: "[VERSION] [PROBLEM SUMMARY]" -labels: bug -assignees: finorr ---- - -## Expected Behavior - -Please describe the behavior you are expecting - -## Current Behavior - -What is the current behavior? - -## Context - -Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions. - -* Project Version: -* Operating System: -* Toolchain: -* Toolchain version: - -## Failure Information (for bugs) - -Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template. - -### Steps to Reproduce - -Please provide detailed steps for reproducing the issue. - -1. step 1 -2. step 2 -3. you get it... - -### Failure Logs - -Please include any relevant log snippets or files here. - -## Checklist - -- [ ] I am running the latest version -- [ ] I checked the documentation and found no answer -- [ ] I checked to make sure that this issue has not already been filed -- [ ] I'm reporting the issue to the correct repository (for multi-repository projects) -- [ ] I have provided sufficient information for the team diff --git a/.github/ISSUE_TEMPLATE/QUESTION.md b/.github/ISSUE_TEMPLATE/QUESTION.md deleted file mode 100644 index 133e7e1..0000000 --- a/.github/ISSUE_TEMPLATE/QUESTION.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: Question -about: Use this template to ask a question about the project -title: "[QUESTION SUMMARY]" -labels: question -assignees: finorr ---- - -## Question - -State your question - -## Sample Code - -Please include relevant code snippets or files that provide context for your question. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 3ba13e0..0000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1 +0,0 @@ -blank_issues_enabled: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 9098e60..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,21 +0,0 @@ -# Description - -Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. - -Fixes # (issue) - -# How Has This Been Tested? - -Please describe the tests that you ran to verify your changes. Please also note any relevant details for your test configuration. - -- [ ] Test A -- [ ] Test B - -# Checklist: - -- [ ] My code follows the style guidelines of this project -- [ ] I have performed a self-review of my own code -- [ ] I have commented my code, particularly in hard-to-understand areas -- [ ] I have made corresponding changes to the documentation -- [ ] My changes generate no new warnings -- [ ] Any dependent changes have been merged and published in downstream modules diff --git a/.github/PULL_REQUEST_TEMPLATE/ccc.md b/.github/PULL_REQUEST_TEMPLATE/ccc.md deleted file mode 100644 index 6587d3f..0000000 --- a/.github/PULL_REQUEST_TEMPLATE/ccc.md +++ /dev/null @@ -1,49 +0,0 @@ -# Pull Request Template - Code Change Control - -## Description - -Please include a summary of the change and which issue is fixed. Please provide the motivation for why this change is necessary at this stage of the product development cycle. - -Fixes # (issue) - -## Customer Impact - -Please describe any customer facing impact of this change. This can be positive or negative impact. - -## Performance Impact - -Please describe any relevant performance impact of this change. This can be positive or negative impact. How did you characterize/test the performance impact? - -## How Has This Been Tested? - -Please describe the tests that you ran to verify your changes. Provide instructions so others can reproduce. Please also list any relevant details for your test configuration. - -- [ ] Test A -- [ ] Test B - -**Hardware Configuration(s) Tested**: - -**Software Configuration(s) Tested**: - -* Operating System: -* Software version: -* Branch: -* Toolchain version: -* SDK version: - -## Reviews - -Please identify two developers to review this change - -- [ ] @personA -- [ ] @personB - -## Checklist: - -- [ ] I have performed a self-review of my own code -- [ ] I have commented my code, particularly in hard-to-understand areas -- [ ] I have made corresponding changes to the documentation -- [ ] My changes generate no new warnings -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] New and existing unit tests pass locally with my changes -- [ ] Any dependent changes have been merged and published in downstream modules diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md deleted file mode 100644 index 62988b9..0000000 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ /dev/null @@ -1,42 +0,0 @@ -# Pull Request Template - -## Description - -Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. - -Fixes # (issue) - -## Type of change - -Please delete options that are not relevant. - -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] This change requires a documentation update - -## How Has This Been Tested? - -Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - -- [ ] Test A -- [ ] Test B - -**Test Configuration(s)**: - -* Firmware version: -* Hardware: -* Toolchain: -* SDK: - -## Checklist: - -- [ ] My code follows the style guidelines of this project -- [ ] I have performed a self-review of my own code -- [ ] I have commented my code, particularly in hard-to-understand areas -- [ ] I have made corresponding changes to the documentation -- [ ] My changes generate no new warnings -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] New and existing unit tests pass locally with my changes -- [ ] Any dependent changes have been merged and published in downstream modules -- [ ] I have checked my code and corrected any misspellings diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c210347 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + push: + branches: ["**"] + pull_request: + branches: ["**"] + +jobs: + build-and-test: + runs-on: ubuntu-24.04 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install build tools + run: | + sudo apt-get update -qq + sudo apt-get install -y -qq gcc g++ cmake make + + - name: Configure (CMake + FetchContent GTest) + run: cmake -B build -DCMAKE_BUILD_TYPE=Release + + - name: Build + run: cmake --build build --parallel "$(nproc)" + + - name: Run tests + run: build/tests/test_polyfit --gtest_output=xml:results.xml + + - name: Publish test results + if: always() + uses: mikepenz/action-junit-report@v4 + with: + report_paths: results.xml + check_name: Google Test Results diff --git a/.gitignore b/.gitignore index e52097a..3e6adbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,49 +1,53 @@ -# Generated Files -**/buildresults/** - -# Sublime-generated Files -*.sublime-workspace - -# VSCode-generated Files -.vscode/** - -######################## -# C / C++ Ignore Rules # -######################## - -# OS Files - -.DS_Store - # Prerequisites *.d -# Compiled Object files -*.slo -*.lo +# Object files *.o +*.ko *.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp # Precompiled Headers *.gch *.pch -# Compiled Dynamic libraries +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll *.so +*.so.* *.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib # Executables *.exe *.out *.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +build/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 2629ec6..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "cmake"] - path = cmake - url = git@github.com:embeddedartistry/cmake-buildsystem.git diff --git a/BuildOptions.cmake b/BuildOptions.cmake deleted file mode 100644 index aef87c0..0000000 --- a/BuildOptions.cmake +++ /dev/null @@ -1,121 +0,0 @@ -################### -# Project Options # -################### - -include(CMakeDependentOption) -include(CheckIPOSupported) - -check_ipo_supported(RESULT lto_supported) -if("${lto_supported}") - option(ENABLE_LTO - "Enable link-time optimization" - OFF) -endif() - -if(NOT ("${ENABLE_LTO}" AND (${CMAKE_C_COMPILER_ID} STREQUAL Clang OR ${CMAKE_C_COMPILER_ID} STREQUAL AppleClang))) - set(OPTION_DISABLE_BUILTINS_IS_ENABLED True) -else() - set(OPTION_DISABLE_BUILTINS_IS_ENABLED False) -endif() - -option(DISABLE_RTTI - "Disable runtime type information (RTTI) for C++." - OFF) -option(DISABLE_EXCEPTIONS - "Disable exception handling for C++." - OFF) -option(ENABLE_PEDANTIC - "Enable pedantic compiler warnings." - OFF) -option(ENABLE_PEDANTIC_ERROR - "Enable pedantic compiler warnings, and treat them as errors." - OFF) -option(DISABLE_STACK_PROTECTION - "Disable stack smashing protection (-fno-stack-protector)." - ON) -CMAKE_DEPENDENT_OPTION(PROJECTVARNAME_BUILD_TESTING - "Enable testing even when this project is used as an external project." - OFF - "NOT CMAKE_CROSSCOMPILING" OFF) -CMAKE_DEPENDENT_OPTION(DISABLE_BUILTINS - "Disable compiler builtins (-fno-builtin)." - OFF - "${OPTION_DISABLE_BUILTINS_IS_ENABLED}" - ON) - -################### -# Process Options # -################### - -if((NOT CMAKE_CROSSCOMPILING) AND BUILD_TESTING AND - (PROJECTVARNAME_BUILD_TESTING OR (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME))) - message("Enabling tests.") - set(PROJECTVARNAME_TESTING_IS_ENABLED ON CACHE INTERNAL "Logic that sets whether testing is enabled on this project") -endif() - -if("${ENABLE_LTO}") - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) -endif() - -if(DISABLE_RTTI) - add_compile_options(-fno-rtti) -endif() - -if(DISABLE_EXCEPTIONS) - add_compile_options(-fno-exceptions -fno-unwind-tables) -endif() - -if(DISABLE_BUILTINS) - add_compile_options(-fno-builtin) -endif() - -if(DISABLE_STACK_PROTECTION) - add_compile_options(-fno-stack-protector) -endif() - -if(ENABLE_PEDANTIC) - add_compile_options(-pedantic) -endif() - -if(ENABLE_PEDANTIC_ERROR) - add_compile_options(-pedantic-error) -endif() - -############################################## -# Default Settings for CMake Cache Variables # -############################################## - -# Set a default build type if none was specified -set(default_build_type "RelWithDebInfo") -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to '${default_build_type}' as none was specified.") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE - STRING "Choose the type of build." - FORCE - ) - # Set the possible values of build type for cmake-gui/ccmake - set_property(CACHE CMAKE_BUILD_TYPE - PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo" - ) -endif() - -set(default_pic ON) -if("${CMAKE_POSITION_INDEPENDENT_CODE}" STREQUAL "") - message(STATUS "Setting PIC for all targets to '${default_pic}' as no value was specified.") - set(CMAKE_POSITION_INDEPENDENT_CODE ${default_pic} CACHE - BOOL "Compile all targets with -fPIC" - FORCE - ) -endif() - -set(default_shared_libs OFF) -if("${BUILD_SHARED_LIBS}" STREQUAL "") - message(STATUS "Setting 'build shared libraries' to '${default_shared_libs}' as no value was specified.") - set(BUILD_SHARED_LIBS ${default_shared_libs} CACHE - BOOL "Compile shared libraries by default instead of static libraries." - FORCE - ) -endif() - -# Export compile_commands.json file. -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/CMakeLists.txt b/CMakeLists.txt index b3d54dc..40875ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,104 +1,13 @@ -cmake_minimum_required(VERSION 3.17) -project(polyfit - VERSION 0.1 - DESCRIPTION "POLYFIT" - LANGUAGES C CXX ASM) +cmake_minimum_required(VERSION 3.14) +project(polyfit C CXX) -set_property(GLOBAL PROPERTY C_STANDARD 11) -set_property(GLOBAL PROPERTY CXX_STANDARD 20) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) -################# -# Build Modules # -################# +# Build polyfit as a static library so both the demo and tests can link it +add_library(polyfit STATIC polyfit.c) +target_include_directories(polyfit PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(polyfit PUBLIC m) -if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR PROJECTVARNAME_BUILD_TESTING) - include(CTest) -endif() - -# Define and Process Project Options -include(BuildOptions.cmake) - -# Dependency manager -include(cmake/CPM.cmake) -# Improved functions for checking compiler/linker flag support -include(cmake/compiler/CheckAndApplyFlags.cmake) -# Adds a function for generating a linker map -include(cmake/linker/map.cmake) -# Overrides add_executable so that linker script dependencies are registered automatically -include(cmake/linker/AddExecutableWithLinkerScriptDep.cmake) -# Provides functions to convert ELF files into .bin and .hex -include(cmake/Conversions.cmake) -# Enable code coverage analysis support -include(cmake/analysis/coverage.cmake) -# Enable code sanitizer build support -include(cmake/analysis/sanitizers.cmake) - -# Enable CMocka support if testing is enabled -if(PROJECTVARNAME_TESTING_IS_ENABLED) - include(cmake/test/cmocka.cmake) -endif() - -# Enable Catch2 Support if testing is enabled -if(PROJECTVARNAME_TESTING_IS_ENABLED) - include(cmake/test/catch2.cmake) -endif() - -# Specifies default compiler flags for the project -include(cmake/compiler/DefaultCompilerSettings.cmake) -# Specifies default linker flags for the project -include(cmake/linker/DefaultLinkerSettings.cmake) - -# Define Packaging Rules -include(Packaging.cmake) - -######################### -# External Dependencies # -######################### - -# You can set an ETL_PROFILE variable option to control the profile header to include -# The library is called etl -CPMAddPackage( - NAME etl - GIT_REPOSITORY git@github.com:ETLCPP/etl.git - GIT_TAG master - OPTIONS - "BUILD_TESTS OFF" -) - -########################## -# Enable Static Analysis # -########################## - -# Provides cppcheck targets and an option to compile with cppcheck analysis -include(cmake/analysis/cppcheck.cmake) -# Provides clang-tidy targets and and option to compile with clang-tidy analysis -include(cmake/analysis/clang-tidy.cmake) - -####################### -# Process Source Tree # -####################### - -add_subdirectory(src) - -##################### -# Process Test Tree # -##################### - -add_subdirectory(test) - -################### -# Tooling Targets # -################### - -# Provides clang-format build targets -include(cmake/format/clang-format.cmake) -# Provides complexity analysis targets -include(cmake/analysis/complexity.cmake) -# Defines code coverage analysis targets -enable_coverage_targets(polyfit_tests) -# Provides Doxygen documentation generation target -include(cmake/documentation/doxygen.cmake) -# Provides SLOCCount targets -include(cmake/analysis/sloccount.cmake) -# Provides vale documentation linting target -include(cmake/analysis/vale.cmake) +enable_testing() +add_subdirectory(tests) diff --git a/docs/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 95% rename from docs/CONTRIBUTING.md rename to CONTRIBUTING.md index 69e5010..f5968bf 100644 --- a/docs/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to PolyFit Extrapolator -Thank you for your interest in contributing to PolyFit! +Thank you for your interest in contributing to PolyFitExtrapolator! By contributing to this project, you help make it better. ## How to Contribute diff --git a/LICENSE b/LICENSE index 261eeb9..905c485 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,21 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +MIT License + +Copyright (c) 2024 Fin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile deleted file mode 100644 index ce262e3..0000000 --- a/Makefile +++ /dev/null @@ -1,203 +0,0 @@ -# you can set this to 1 to see all commands that are being run -VERBOSE ?= 0 - -ifeq ($(VERBOSE),1) -export Q := -export VERBOSE := 1 -else -export Q := @ -export VERBOSE := 0 -endif - -BUILDRESULTS ?= buildresults -CONFIGURED_BUILD_DEP = $(BUILDRESULTS)/build.ninja - -# This skeleton is built for CMake's Ninja generator -export CMAKE_GENERATOR=Ninja - -OPTIONS ?= -INTERNAL_OPTIONS = - -CPM_CACHE?=$(HOME)/CPM_Cache -ifneq ($(CPM_CACHE),) - INTERNAL_OPTIONS += -DCPM_SOURCE_CACHE=$(CPM_CACHE) -endif - -LTO ?= 0 -ifeq ($(LTO),1) - INTERNAL_OPTIONS += -DENABLE_LTO=ON -endif - -CROSS ?= -ifneq ($(CROSS),) - INTERNAL_OPTIONS += -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/cross/$(CROSS).cmake -endif - -NATIVE ?= -ifneq ($(NATIVE),) - INTERNAL_OPTIONS += -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/native/$(NATIVE).cmake -endif - -BUILD_TYPE ?= -ifneq ($(BUILD_TYPE),) - INTERNAL_OPTIONS += -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -endif - -SANITIZER ?= -ifneq ($(SANITIZER),) - INTERNAL_OPTIONS += -DUSE_SANITIZER=$(SANITIZER) -endif - -all: default - -.PHONY: default -default: | $(CONFIGURED_BUILD_DEP) - $(Q)ninja -C $(BUILDRESULTS) - -.PHONY: test -test: default - $(Q)cd $(BUILDRESULTS); ctest - -.PHONY: docs -docs: | $(CONFIGURED_BUILD_DEP) - $(Q)ninja -C $(BUILDRESULTS) docs - -.PHONY: package -package: default - $(Q)ninja -C $(BUILDRESULTS) package - $(Q)ninja -C $(BUILDRESULTS) package_source - -.PHONY: cppcheck -cppcheck: | $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) cppcheck - -.PHONY: cppcheck-xml -cppcheck-xml: | $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) cppcheck-xml - -.PHONY: complexity -complexity: | $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) complexity - -.PHONY: complexity-xml -complexity-xml: | $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) complexity-xml - -.PHONY: complexity-full -complexity-full: | $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) complexity-full - -.PHONY: tidy -tidy: $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) tidy - -.PHONY: format -format: $(CONFIGURED_BUILD_DEP) - $(Q)ninja -C $(BUILDRESULTS) format - -.PHONY : format-patch -format-patch: $(CONFIGURED_BUILD_DEP) - $(Q)ninja -C $(BUILDRESULTS) format-patch - -.PHONY: scan-build -scan-build: - $(Q) scan-build cmake -B $(BUILDRESULTS)/scan-build $(OPTIONS) $(INTERNAL_OPTIONS) - $(Q) ninja -C $(BUILDRESULTS)/scan-build - -.PHONY: coverage -coverage: - $(Q) cmake -B $(BUILDRESULTS)/coverage -DCMAKE_BUILD_TYPE=Debug -DENABLE_COVERAGE_ANALYSIS=ON $(OPTIONS) $(INTERNAL_OPTIONS) - $(Q) ninja -C $(BUILDRESULTS)/coverage - $(Q) cd $(BUILDRESULTS)/coverage; ctest - $(Q) ninja -C $(BUILDRESULTS)/coverage coverage - -.PHONY: sloccount -sloccount: $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) sloccount - -.PHONY: sloccount-full -sloccount-full: $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) sloccount-full - -.PHONY: sloccount-report -sloccount-report: $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) sloccount-report - -.PHONY: sloccount-report-full -sloccount-full-report: $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) sloccount-report-full - -.PHONY: vale -vale: $(CONFIGURED_BUILD_DEP) - $(Q) ninja -C $(BUILDRESULTS) vale - -# Runs whenever the build has not been configured successfully -$(CONFIGURED_BUILD_DEP): - $(Q)cmake -B $(BUILDRESULTS) $(OPTIONS) $(INTERNAL_OPTIONS) - -# Manually Reconfigure a target, esp. with new options -.PHONY: reconfig -reconfig: - $(Q) cmake -B $(BUILDRESULTS) $(OPTIONS) $(INTERNAL_OPTIONS) - -.PHONY: clean -clean: - $(Q) if [ -d "$(BUILDRESULTS)" ]; then ninja -C $(BUILDRESULTS) clean; fi - -.PHONY: distclean -distclean: - $(Q) rm -rf $(BUILDRESULTS) - -.PHONY : help -help : - @echo "usage: make [OPTIONS] " - @echo " Options:" - @echo " > VERBOSE Show verbose output for Make rules. Default 0. Enable with 1." - @echo " > BUILDRESULTS Directory for build results. Default buildresults." - @echo " > OPTIONS Configuration options to pass to a build. Default empty." - @echo " > LTO Enable LTO builds. Default 0. Enable with 1." - @echo " > CROSS Enable a Cross-compilation build. " - @echo " Pass the cross-compilation toolchain name without a path or extension." - @echo " Example: make CROSS=cortex-m3" - @echo " For supported toolchains, see cmake/toolchains/cross/" - @echo " > NATIVE Use an alternate toolchain on your build machine. " - @echo " Pass the toolchain name without a path or extension." - @echo " Example: make CROSS=gcc-9" - @echo " For supported toolchains, see cmake/toolchains/native/" - @echo " > CPM_CACHE Specify the path to the CPM source cache." - @echo " Set the variable to an empty value to disable the cache." - @echo " > BUILD_TYPE Specify the build type (default: RelWithDebInfo)" - @echo " Option are: Debug Release MinSizeRel RelWithDebInfo" - @echo " > SANITIZER Compile with support for a Clang/GCC Sanitizer." - @echo " Options are: none (default), address, thread, undefined, memory," - @echo " leak, and 'address,undefined' as a combined option" - @echo "Targets:" - @echo " default: Builds all default targets ninja knows about" - @echo " test: Build and run unit test programs" - @echo " docs: Generate documentation" - @echo " package: Build the project, generates docs, and create a release package" - @echo " clean: cleans build artifacts, keeping build files in place" - @echo " distclean: removes the configured build output directory" - @echo " reconfig: Reconfigure an existing build output folder with new settings" - @echo "Static Analysis:" - @echo " cppcheck: runs cppcheck" - @echo " cppcheck-xml: runs cppcheck and generates an XML report (for build servers)" - @echo " Code Formating:" - @echo " format: runs clang-format on codebase" - @echo " format-patch: generates a patch file with formatting changes" - @echo " Static Analysis:" - @echo " cppcheck: runs cppcheck" - @echo " cppcheck-xml: runs cppcheck and generates an XML report (for build servers)" - @echo " scan-build: runs clang static analysis" - @echo " complexity: runs complexity analysis with lizard, only prints violations" - @echo " complexity-full: runs complexity analysis with lizard, prints full report" - @echo " complexity-xml: runs complexity analysis with lizard, generates XML report" - @echo " (for build servers)" - @echo " coverage: runs code coverage analysis and generates an HTML & XML reports" - @echo " tidy: runs clang-tidy linter" - @echo " sloccount: Run SLOCCount analysis on project." - @echo " sloccount: Run SLOCCount analysis on project with detailed output." - @echo " sloccount-report: Run SLOCCount analysis on project and save the results to a file." - @echo " sloccount-report-full: Run SLOCCount analysis on project with detailed output" - @echo " save the results to a file." - @echo " vale: Run vale documentation linting." diff --git a/Packaging.cmake b/Packaging.cmake deleted file mode 100644 index 6d64340..0000000 --- a/Packaging.cmake +++ /dev/null @@ -1,30 +0,0 @@ -#################### -# Packaging Module # -#################### - -### General Configuration ### - -set(CPACK_PACKAGE_VENDOR "Embedded Artistry") -set(CPACK_GENERATOR "ZIP;TBZ2") -set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}/packages") - -set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${CMAKE_SYSTEM_PROCESSOR}") -if(CPU_NAME) - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CPU_NAME}") -endif() -if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Generic") - set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CMAKE_SYSTEM_NAME}") -endif() -set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CMAKE_PROJECT_VERSION}") - -### Source Packaging Configuration ### - -set(CPACK_SOURCE_GENERATOR "ZIP;TBZ2") -set(CPACK_SOURCE_IGNORE_FILES - "${CMAKE_BINARY_DIR}" - ".DS_Store" - "/.git*/" -) - -### INCLUDE ALL SETTINGS BEFORE THIS LINE -include(CPack) diff --git a/README.md b/README.md index bbf8217..0b023aa 100644 --- a/README.md +++ b/README.md @@ -1,267 +1,162 @@ # PolyFit [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![GitHub top language](https://img.shields.io/github/languages/top/FinOrr/polyfit.svg)](https://github.com/FinOrr/polyfit) -[![GitHub issues](https://img.shields.io/github/issues/FinOrr/polyfit.svg)](https://github.com/FinOrr/polyfit/issues) -[![GitHub pull requests](https://img.shields.io/github/issues-pr/FinOrr/polyfit.svg)](https://github.com/FinOrr/polyfit/pulls) +[![Top Language](https://img.shields.io/github/languages/top/FinOrr/polyfit.svg)](https://github.com/FinOrr/polyfit) +[![Issues](https://img.shields.io/github/issues/FinOrr/polyfit.svg)](https://github.com/FinOrr/polyfit/issues) +[![Pull Requests](https://img.shields.io/github/issues-pr/FinOrr/polyfit.svg)](https://github.com/FinOrr/polyfit/pulls) -## Overview +A lightweight C library for fitting polynomials to data—fast, simple, and no external dependencies. -**PolyFit** is a C library designed to facilitate accurate polynomial fitting for curve approximation, allowing for interpolation and extrapolation of data. With just a few input datapoints, you can model your system quickly and efficiently. +## What is it? -## Features - -- Polynomial fitting for curve approximation. - -- Interpolation and extrapolation functionality for predicting additional data points. - -- Lightweight and easy-to-integrate into existing C projects. - -## Table of Contents - -1. [Use Case Scenarios](#use-case-scenarios) -2. [Project Status](#project-status) -3. [Getting Started](#getting-started) - 1. [Requirements](#requirements) - 1. [git-lfs](#git-lfs) - 1. [CMake Build System](#cmake-build-system) - 2. [Getting the Source](#getting-the-source) - 3. [Building](#building) - 4. [Testing](#testing) -5. [Documentation](#documentation) -6. [Need Help?](#need-help) -7. [Contributing](#contributing) -8. [Further Reading](#further-reading) -9. [Authors](#authors) -10. [License](#license) -11. [Acknowledgments](#acknowledgements) - -## Use Case Scenarios - -Sound a bit asbtract? No worries, here's some examples of where PolyFit can help: - -**Curve Fitting in Data Analysis** -- In climate science research, polynomial curve fitting is applied to analyse historical temperature data and predict future climate trends, aiding in understanding global warming patterns. - -**Signal Processing and Filtering** -- Biomedical engineers use polynomial filters to remove noise from electroencephalogram (EEG) signals within neuroscience research, improving the detection of brainwave patterns and facilitating the diagnosis of neurological disorders. +**PolyFit** is a small, embeddable C library for polynomial regression. +It helps you fit a curve through a set of data points so you can interpolate or extrapolate with minimal effort. -**Financial Modeling and Time Series Analysis** -- Financial analysts utilise polynomial regression models to analyse market data and predict prices. For example, in investment banking, polynomial models are employed to forecast future stock prices, aiding investors in making informed trading decisions. +Use PolyFit for signal smoothing, approximating system behavior, or forming simple transfer-function polynomials. Include the two source files and call the API; no extra setup required. -**Robotics and Path Planning** -- Autonomous drones use polynomial trajectories for path planning in search and rescue missions. For instance, in disaster response scenarios, drones navigate through complex environments by following smooth polynomial paths, enabling efficient search operations and rescuing survivors. Think: - - feature trajectory estimation; - - motion model for localisation; - - map building and refinement; and - - sensor calibration. +--- -**Transform Functions and Control Systems** -- Polynomial models are vital in representing system transfer functions, which describe the relationship between inputs and outputs of a dynamic system. By mapping polynomials to transfer functions, engineers can model the behavior of diverse systems across various domains, including aerospace, automotive, and industrial control. +## Where It’s Useful -- Engineers can use transfer functions derived from polynomials to perform advanced control systems analysis techniques, such as Root-Locus, freq response analysis, and pole-zero analysis to achieve desired performance objectives, such as stability, responsiveness, and robustness. +Here's a few real-world uses: -**Control System Applications** -- In industrial automation, polynomial controllers regulate motors by translating input commands into precise motor outputs. -- By applying specific inputs and measuring corresponding outputs, such as speed or torque, engineers optimise manufacturing processes. -- For example, in controlling fluid pump outputs, polynomial controllers enable adjustments to achieve desired pressure levels or flow rates, enhancing efficiency and product quality. +### Signal Processing +Useful in cleaning up noisy data e.g., smoothing biomedical signals like EEGs. -**[Back to top](#table-of-contents)** +### Robotics & Navigation +Model sensor noise, trajectory paths, or estimate system motion with smooth, continuous polynomials. -# Project Status +### Control Systems +Originally built to model dynamic systems using polynomial-based transfer functions. Great for: +- Root locus +- Frequency response +- Pole-zero plots -The current system requires the user to specify the desired order of polynomial to be fit to the data. -Future releases will focus on auto-detecting the most suitable, lowest-order polynomial. +--- -**[Back to top](#table-of-contents)** - -## Getting Started - -### Requirements - -At a minimum you will need: - -* [`git-lfs`](https://git-lfs.github.com), which is used to store binary files in this repository -* [CMake](#cmake-build-system) is the build system -* Some kind of compiler for your target system. - - This repository has been tested with: - - gcc-7, gcc-8, gcc-9 - - arm-none-eabi-gcc - - Apple clang - - Mainline clang - -#### git-lfs - -This project stores some files using [`git-lfs`](https://git-lfs.github.com). - -To install `git-lfs` on Linux: - -``` -sudo apt install git-lfs -``` - -To install `git-lfs` on OS X: - -``` -brew install git-lfs -``` - -Additional installation instructions can be found on the [`git-lfs` website](https://git-lfs.github.com). - -#### CMake Build System - -The official way to install CMake is to use the pre-compiled binaries and installers on the [CMake download page](https://cmake.org/download/). You can also [compile CMake from source](https://cmake.org/install/). CMake can also be installed through popular package managers, although they may be slightly behind the latest release available on the website. - -You can install CMake with `apt` on Linux/WSL: - -``` -sudo apt-get install cmake -``` - -> **Note:** Does this not work? You may need to add an [apt repository](https://apt.kitware.com/). - -OS X users can install CMake using [Homebrew](homebrew): - -``` -brew install cmake -``` - -You can also use Python's `pip` to install CMake: - -``` -$ pip3 install cmake -``` - -Make is the default backend for CMake, but our Makefile interface defaults to Ninja. Ninja is similar in purpose to Make, but provides better performance. - -To install Ninja on Linux & WSL: - -``` -$ sudo apt install ninja-build -``` - -To install on OSX: - -``` -$ brew install ninja -``` +## Features +- Polynomial curve fitting with configurable order +- Supports both interpolation and extrapolation +- Single-file: just drop in `polyfit.c` and `polyfit.h` +- No dependencies beyond the standard library -**[Back to top](#table-of-contents)** +--- -### Getting the Source +## Quickstart -This project uses [`git-lfs`](https://git-lfs.github.com), so please install it before cloning. If you cloned prior to installing `git-lfs`, simply run `git lfs pull` after installation. +### Clone the Repo -This project is hosted on GitHub. You can clone the project directly using this command: +```bash +git clone https://github.com/FinOrr/polyfit.git +```` -``` -git clone --recursive git@github.com:finorr/polyfit.git -``` +Then just copy `polyfit.c` and `polyfit.h` into your project. -If you don't clone recursively, be sure to run the following command in the repository or your build will fail: +### Include It +```c +#include "polyfit.h" ``` -git submodule update --init -``` - -**[Back to top](#table-of-contents)** -### Building - -If Make is installed, the library can be built by issuing the following command: - -``` -make -``` +### Basic Usage -This will build all targets for your current architecture. +**Example 1: Simple linear fit (recommended)** -You can clean builds using: +```c +#include "polyfit.h" +#include -``` -make clean -``` +int main(void) { + // Your data points + float x[] = {1.0, 2.0, 3.0, 4.0, 5.0}; + float y[] = {2.1, 3.9, 6.1, 8.0, 9.9}; -You can eliminate the generated `buildresults` folder using: + // Fit a linear polynomial (degree 1) + Polynomial *poly = polyfit(x, y, 5, 1, NULL); + if (poly) { + float result; + polyfit_evaluate(poly, 6.0f, &result); + printf("f(6.0) = %f\n", result); // Predict at x=6 + polyfit_free(poly); + } -``` -make distclean + return 0; +} ``` -You can also use `CMake` directly for compiling. +**Example 2: One-shot evaluation (no memory management)** -Create a build output folder: +```c +// Fit and evaluate in one call - perfect for quick predictions +float x[] = {0.0, 1.0, 2.0, 3.0}; +float y[] = {1.0, 2.0, 5.0, 10.0}; +float result; -``` -cmake -B buildresults +if (polyfit_eval_at(x, y, 4, 2, 4.0f, &result) == POLYFIT_SUCCESS) { + printf("f(4.0) = %f\n", result); +} ``` -And build all targets by running +**Example 3: Extract coefficients** -``` -ninja -C buildresults +```c +Polynomial *poly = polyfit(x, y, 5, 2, NULL); +if (poly) { + float coeffs[3]; // degree + 1 + if (polyfit_get_coefficients(poly, coeffs, 3) == POLYFIT_SUCCESS) { + printf("y = %.2f + %.2f*x + %.2f*x^2\n", + coeffs[0], coeffs[1], coeffs[2]); + } + polyfit_free(poly); +} ``` -Cross-compilation is handled using CMake toolchain files. Example files are included in the [`cmake/toolchains/cross`](cmake/toolchains/cross/) folder. You can write your own cross files for your specific processor by defining the toolchain, compilation flags, and linker flags. These settings will be used to compile the project. +**Example 4: Error handling** -Cross-compilation must be configured using the CMake command when creating the build output folder. For example: - -``` -cmake -B buildresults -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/cross/cortex-m3.cmake +```c +polyfit_error_t err; +Polynomial *poly = polyfit(x, y, num_points, degree, &err); +if (!poly) { + fprintf(stderr, "Error: %s\n", polyfit_error_string(err)); + return -1; +} +// Use polynomial... +polyfit_free(poly); ``` -Following that, you can run `make` (at the project root) or `ninja` to build the project. - -Tests will not be cross-compiled. They will only be built for the native platform. +### Integration -**[Back to top](#table-of-contents)** +Just copy these two files into your project: +- `polyfit.c` +- `polyfit.h` -### Testing +Then compile with your source code: -The tests for this project are written in CMocka and Catch, which are included as external dependencies and does not need to be installed on your system. You can run the tests by issuing the following command: - -``` -make test +```bash +gcc -o myapp main.c polyfit.c -lm ``` -By default, test results are generated for use by the CI server and are formatted in JUnit XML. The test results XML files can be found in `buildresults/test/`. - -**[Back to top](#table-of-contents)** +--- ## Documentation -Documentation can be built locally by running the following command: - -``` -make docs -``` - -Documentation can be found in `buildresults/docs`, and the root page is `index.html`. +More detailed info and examples are available on the [Wiki](https://github.com/FinOrr/polyfit/wiki). -**[Back to top](#table-of-contents)** - -## Need help? - -For any inquiries or support, please use the [Issues](https://github.com/FinOrr/polyfit/issues) page. - -If you need further assistance or have any questions, please file a GitHub issue or [send me an email](mailto:3ikxlgcis@mozmail.com). +--- ## Contributing -If you are interested in contributing to this project, please read our [contributing guidelines](docs/CONTRIBUTING.md). - -## Authors +Found a bug? Want to improve performance or add features? PRs welcome, just read the [contributing guide](CONTRIBUTING.md) first. -* Polyfit source code - **[Fin Orr](https://github.com/finorr)** -* CMake Repo Design - **[Phillip Johnston](https://github.com/phillipjohnston)** +--- ## License -See the [LICENSE](LICENSE) file for licensing details. +MIT. See [LICENSE](LICENSE) for full details. -## Acknowledgments +--- -This repository was built using the [CMake repository template](https://github.com/embeddedartistry/cmake-project-skeleton) from the team at Embedded Artistry. +## Questions? -**[Back to top](#table-of-contents)** +Open an [issue](https://github.com/FinOrr/polyfit/issues) if you get stuck or want to ask anything. diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md deleted file mode 100644 index cae100e..0000000 --- a/docs/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,5 +0,0 @@ -# Contributor Code of Conduct - -The latest version of the [Embedded Artistry Code of Conduct](https://embeddedartistry.com/fieldatlas/embedded-artistry-code-of-conduct/) is found on [our website](https://embeddedartistry.com/fieldatlas/embedded-artistry-code-of-conduct/). - -All contributors and community members are expected to adhere to [the Code](https://embeddedartistry.com/fieldatlas/embedded-artistry-code-of-conduct/). diff --git a/polyfit.c b/polyfit.c new file mode 100644 index 0000000..066a958 --- /dev/null +++ b/polyfit.c @@ -0,0 +1,614 @@ +/** + ****************************************************************************** + * @file polyfit.c + * @brief Implementation of polynomial fitting and evaluation library + * @version 1.0 + * @date 2025 + ****************************************************************************** + * @attention + * + * This implementation provides robust polynomial fitting using least squares + * regression with proper error handling and memory management. + * + ****************************************************************************** + */ + +#include "polyfit.h" +#include + +/*============================================================================*/ +/* PRIVATE FUNCTION DECLARATIONS */ +/*============================================================================*/ + +static polyfit_error_t gaussian_elimination(float** A, float* B, float* x, + int32_t n); +static polyfit_error_t allocate_matrix(float*** matrix, int32_t rows, + int32_t cols); +static void free_matrix(float** matrix, int32_t rows); +static polyfit_error_t validate_input_arrays(const float* x, const float* y, + int32_t num_points); + +/*============================================================================*/ +/* PUBLIC FUNCTION IMPLEMENTATIONS */ +/*============================================================================*/ + +Polynomial* polyfit_init(int32_t degree) { + if (degree < 0 || degree > POLYFIT_MAX_DEGREE) { + return NULL; + } + + Polynomial* poly = (Polynomial*)malloc(sizeof(Polynomial)); + if (poly == NULL) { + return NULL; + } + + poly->coefficients = (float*)calloc(degree + 1, sizeof(float)); + if (poly->coefficients == NULL) { + free(poly); + return NULL; + } + + poly->degree = degree; + poly->is_valid = true; + + return poly; +} + +void polyfit_free(Polynomial* poly) { + if (poly != NULL) { + free(poly->coefficients); + poly->coefficients = NULL; + poly->degree = -1; + poly->is_valid = false; + free(poly); + } +} + +polyfit_error_t polyfit_least_squares(const float* x, const float* y, + int32_t num_points, int32_t degree, + Polynomial* result_poly) { + // Input validation + if (x == NULL || y == NULL || result_poly == NULL) { + return POLYFIT_ERROR_NULL_POINTER; + } + + if (degree < 0 || degree > POLYFIT_MAX_DEGREE) { + return POLYFIT_ERROR_INVALID_DEGREE; + } + + if (num_points <= degree) { + return POLYFIT_ERROR_INSUFFICIENT_POINTS; + } + + polyfit_error_t error = validate_input_arrays(x, y, num_points); + if (error != POLYFIT_SUCCESS) { + return error; + } + + // Allocate matrices + float** A = NULL; + float* B = NULL; + + error = allocate_matrix(&A, degree + 1, degree + 1); + if (error != POLYFIT_SUCCESS) { + return error; + } + + B = (float*)calloc(degree + 1, sizeof(float)); + if (B == NULL) { + free_matrix(A, degree + 1); + return POLYFIT_ERROR_MEMORY_ALLOC; + } + + // Build normal equations (A^T * A * coeffs = A^T * y) + for (int32_t i = 0; i <= degree; i++) { + for (int32_t j = 0; j <= degree; j++) { + A[i][j] = 0.0f; + for (int32_t k = 0; k < num_points; k++) { + A[i][j] += polyfit_pow(x[k], i + j); + } + } + + B[i] = 0.0f; + for (int32_t k = 0; k < num_points; k++) { + B[i] += y[k] * polyfit_pow(x[k], i); + } + } + + // Solve the system + error = gaussian_elimination(A, B, result_poly->coefficients, degree + 1); + + // Cleanup + free_matrix(A, degree + 1); + free(B); + + if (error == POLYFIT_SUCCESS) { + result_poly->degree = degree; + result_poly->is_valid = true; + } + + return error; +} + +polyfit_error_t polyfit_evaluate(const Polynomial* poly, float x, + float* result) { + if (poly == NULL || result == NULL) { + return POLYFIT_ERROR_NULL_POINTER; + } + + if (!polyfit_is_valid(poly)) { + return POLYFIT_ERROR_INVALID_INPUT; + } + + *result = 0.0f; + + // Use Horner's method for efficient evaluation + for (int32_t i = poly->degree; i >= 0; i--) { + *result = *result * x + poly->coefficients[i]; + } + + return POLYFIT_SUCCESS; +} + +polyfit_error_t polyfit_get_max_coefficient_magnitude(const Polynomial* poly, + float* max_magnitude) { + if (poly == NULL || max_magnitude == NULL) { + return POLYFIT_ERROR_NULL_POINTER; + } + + if (!polyfit_is_valid(poly)) { + return POLYFIT_ERROR_INVALID_INPUT; + } + + *max_magnitude = 0.0f; + + for (int32_t i = 0; i <= poly->degree; i++) { + float magnitude = polyfit_fabs(poly->coefficients[i]); + if (magnitude > *max_magnitude) { + *max_magnitude = magnitude; + } + } + + return POLYFIT_SUCCESS; +} + +bool polyfit_is_valid(const Polynomial* poly) { + return (poly != NULL && poly->coefficients != NULL && poly->degree >= 0 && + poly->degree <= POLYFIT_MAX_DEGREE && poly->is_valid); +} + +const char* polyfit_error_string(polyfit_error_t error) { + switch (error) { + case POLYFIT_SUCCESS: + return "Success"; + case POLYFIT_ERROR_NULL_POINTER: + return "Null pointer provided"; + case POLYFIT_ERROR_INVALID_DEGREE: + return "Invalid polynomial degree"; + case POLYFIT_ERROR_MEMORY_ALLOC: + return "Memory allocation failed"; + case POLYFIT_ERROR_SINGULAR_MATRIX: + return "Matrix is singular"; + case POLYFIT_ERROR_INSUFFICIENT_POINTS: + return "Insufficient data points"; + case POLYFIT_ERROR_INVALID_INPUT: + return "Invalid input parameters"; + default: + return "Unknown error"; + } +} + +/*============================================================================*/ +/* CONVENIENCE FUNCTION IMPLEMENTATIONS */ +/*============================================================================*/ + +Polynomial* polyfit(const float* x, const float* y, int32_t num_points, + int32_t degree, polyfit_error_t* error) { + polyfit_error_t local_error; + + // Initialize polynomial + Polynomial* poly = polyfit_init(degree); + if (poly == NULL) { + local_error = POLYFIT_ERROR_MEMORY_ALLOC; + if (error != NULL) { + *error = local_error; + } + return NULL; + } + + // Fit the polynomial + local_error = polyfit_least_squares(x, y, num_points, degree, poly); + if (local_error != POLYFIT_SUCCESS) { + polyfit_free(poly); + if (error != NULL) { + *error = local_error; + } + return NULL; + } + + if (error != NULL) { + *error = POLYFIT_SUCCESS; + } + + return poly; +} + +polyfit_error_t polyfit_eval_at(const float* x, const float* y, + int32_t num_points, int32_t degree, + float eval_x, float* result) { + if (result == NULL) { + return POLYFIT_ERROR_NULL_POINTER; + } + + // Fit the polynomial + polyfit_error_t error; + Polynomial* poly = polyfit(x, y, num_points, degree, &error); + if (poly == NULL) { + return error; + } + + // Evaluate at the specified point + error = polyfit_evaluate(poly, eval_x, result); + + // Clean up + polyfit_free(poly); + + return error; +} + +polyfit_error_t polyfit_get_coefficients(const Polynomial* poly, float* coeffs, + int32_t size) { + if (poly == NULL || coeffs == NULL) { + return POLYFIT_ERROR_NULL_POINTER; + } + + if (!polyfit_is_valid(poly)) { + return POLYFIT_ERROR_INVALID_INPUT; + } + + if (size < poly->degree + 1) { + return POLYFIT_ERROR_INVALID_INPUT; + } + + // Copy coefficients to user array + for (int32_t i = 0; i <= poly->degree; i++) { + coeffs[i] = poly->coefficients[i]; + } + + return POLYFIT_SUCCESS; +} + +/*============================================================================*/ +/* FIT QUALITY AND AUTO-DEGREE IMPLEMENTATIONS */ +/*============================================================================*/ + +polyfit_error_t polyfit_compute_residuals(const Polynomial* poly, + const float* x, const float* y, + int32_t num_points, + float* residuals) { + if (poly == NULL || x == NULL || y == NULL || residuals == NULL) { + return POLYFIT_ERROR_NULL_POINTER; + } + + if (!polyfit_is_valid(poly)) { + return POLYFIT_ERROR_INVALID_INPUT; + } + + if (num_points <= 0) { + return POLYFIT_ERROR_INVALID_INPUT; + } + + for (int32_t i = 0; i < num_points; i++) { + float y_hat; + polyfit_error_t err = polyfit_evaluate(poly, x[i], &y_hat); + if (err != POLYFIT_SUCCESS) { + return err; + } + residuals[i] = y_hat - y[i]; + } + + return POLYFIT_SUCCESS; +} + +polyfit_error_t polyfit_r_squared(const Polynomial* poly, const float* x, + const float* y, int32_t num_points, + float* r_squared) { + if (poly == NULL || x == NULL || y == NULL || r_squared == NULL) { + return POLYFIT_ERROR_NULL_POINTER; + } + + if (!polyfit_is_valid(poly)) { + return POLYFIT_ERROR_INVALID_INPUT; + } + + if (num_points <= 0) { + return POLYFIT_ERROR_INVALID_INPUT; + } + + // Compute mean of y + float y_mean = 0.0f; + for (int32_t i = 0; i < num_points; i++) { + y_mean += y[i]; + } + y_mean /= (float)num_points; + + // Compute total and residual sums of squares + float ss_tot = 0.0f; + float ss_res = 0.0f; + + for (int32_t i = 0; i < num_points; i++) { + float y_hat; + polyfit_error_t err = polyfit_evaluate(poly, x[i], &y_hat); + if (err != POLYFIT_SUCCESS) { + return err; + } + float diff_res = y_hat - y[i]; + float diff_tot = y[i] - y_mean; + ss_res += diff_res * diff_res; + ss_tot += diff_tot * diff_tot; + } + + if (ss_tot < 1e-20f) { + *r_squared = (ss_res < 1e-20f) ? 1.0f : 0.0f; + return POLYFIT_SUCCESS; + } + + *r_squared = 1.0f - (ss_res / ss_tot); + + return POLYFIT_SUCCESS; +} + +Polynomial* polyfit_best_degree(const float* x, const float* y, + int32_t num_points, int32_t max_degree, + int32_t* best_degree, + polyfit_error_t* error) { + if (x == NULL || y == NULL || best_degree == NULL) { + if (error != NULL) { + *error = POLYFIT_ERROR_NULL_POINTER; + } + return NULL; + } + + if (max_degree < 1 || max_degree > POLYFIT_MAX_DEGREE) { + if (error != NULL) { + *error = POLYFIT_ERROR_INVALID_DEGREE; + } + return NULL; + } + + if (num_points <= max_degree) { + if (error != NULL) { + *error = POLYFIT_ERROR_INSUFFICIENT_POINTS; + } + return NULL; + } + + Polynomial* best_poly = NULL; + float best_bic = 0.0f; + float fn = (float)num_points; + + for (int32_t d = 1; d <= max_degree; d++) { + polyfit_error_t local_err; + Polynomial* poly = polyfit(x, y, num_points, d, &local_err); + if (poly == NULL) { + continue; + } + + // Compute residual sum of squares + float ss_res = 0.0f; + for (int32_t i = 0; i < num_points; i++) { + float y_hat; + if (polyfit_evaluate(poly, x[i], &y_hat) == POLYFIT_SUCCESS) { + float diff = y_hat - y[i]; + ss_res += diff * diff; + } + } + + // BIC = n * ln(RSS/n) + (d+1) * ln(n) + float bic; + if (ss_res < 1e-30f) { + bic = -1e30f; // Near-perfect fit + } else { + bic = fn * logf(ss_res / fn) + (float)(d + 1) * logf(fn); + } + + if (best_poly == NULL || bic < best_bic) { + best_bic = bic; + *best_degree = d; + polyfit_free(best_poly); + best_poly = poly; + } else { + polyfit_free(poly); + } + } + + if (best_poly == NULL) { + if (error != NULL) { + *error = POLYFIT_ERROR_SINGULAR_MATRIX; + } + return NULL; + } + + if (error != NULL) { + *error = POLYFIT_SUCCESS; + } + + return best_poly; +} + +/*============================================================================*/ +/* UTILITY FUNCTION IMPLEMENTATIONS */ +/*============================================================================*/ + +float polyfit_pow(float base, int32_t exponent) { + // Handle special cases + if (exponent == 0) { + return 1.0f; + } + + if (base == 0.0f) { + return (exponent > 0) ? 0.0f : 1.0f; // 0^0 = 1 by convention + } + + if (base == 1.0f) { + return 1.0f; + } + + if (base == -1.0f) { + return (exponent % 2 == 0) ? 1.0f : -1.0f; + } + + // Use binary exponentiation + float result = 1.0f; + float current_base = base; + int32_t abs_exponent = (exponent < 0) ? -exponent : exponent; + + while (abs_exponent > 0) { + if (abs_exponent & 1) { + result *= current_base; + } + current_base *= current_base; + abs_exponent >>= 1; + } + + return (exponent < 0) ? (1.0f / result) : result; +} + +float polyfit_fabs(float x) { + // Handle NaN + if (x != x) { + return x; + } + + // Use bit manipulation for efficiency + union { + float f; + uint32_t i; + } u; + + u.f = x; + u.i &= 0x7FFFFFFF; // Clear sign bit + + return u.f; +} + +bool polyfit_is_nearly_zero(float value, float threshold) { + return polyfit_fabs(value) < threshold; +} + +/*============================================================================*/ +/* PRIVATE FUNCTION IMPLEMENTATIONS */ +/*============================================================================*/ + +static polyfit_error_t gaussian_elimination(float** A, float* B, float* x, + int32_t n) { + if (A == NULL || B == NULL || x == NULL || n <= 0) { + return POLYFIT_ERROR_NULL_POINTER; + } + + const float pivot_threshold = 1e-12f; + + // Forward elimination with partial pivoting + for (int32_t i = 0; i < n; i++) { + // Find pivot + int32_t max_row = i; + for (int32_t k = i + 1; k < n; k++) { + if (polyfit_fabs(A[k][i]) > polyfit_fabs(A[max_row][i])) { + max_row = k; + } + } + + // Check for singular matrix + if (polyfit_fabs(A[max_row][i]) < pivot_threshold) { + return POLYFIT_ERROR_SINGULAR_MATRIX; + } + + // Swap rows + if (max_row != i) { + float* temp_row = A[i]; + A[i] = A[max_row]; + A[max_row] = temp_row; + + float temp_b = B[i]; + B[i] = B[max_row]; + B[max_row] = temp_b; + } + + // Eliminate column + for (int32_t k = i + 1; k < n; k++) { + float factor = A[k][i] / A[i][i]; + for (int32_t j = i; j < n; j++) { + A[k][j] -= factor * A[i][j]; + } + B[k] -= factor * B[i]; + } + } + + // Back substitution + for (int32_t i = n - 1; i >= 0; i--) { + x[i] = B[i]; + for (int32_t j = i + 1; j < n; j++) { + x[i] -= A[i][j] * x[j]; + } + x[i] /= A[i][i]; + } + + return POLYFIT_SUCCESS; +} + +static polyfit_error_t allocate_matrix(float*** matrix, int32_t rows, + int32_t cols) { + if (matrix == NULL || rows <= 0 || cols <= 0) { + return POLYFIT_ERROR_NULL_POINTER; + } + + *matrix = (float**)malloc(rows * sizeof(float*)); + if (*matrix == NULL) { + return POLYFIT_ERROR_MEMORY_ALLOC; + } + + for (int32_t i = 0; i < rows; i++) { + (*matrix)[i] = (float*)calloc(cols, sizeof(float)); + if ((*matrix)[i] == NULL) { + // Clean up previously allocated rows + for (int32_t j = 0; j < i; j++) { + free((*matrix)[j]); + } + free(*matrix); + *matrix = NULL; + return POLYFIT_ERROR_MEMORY_ALLOC; + } + } + + return POLYFIT_SUCCESS; +} + +static void free_matrix(float** matrix, int32_t rows) { + if (matrix != NULL) { + for (int32_t i = 0; i < rows; i++) { + free(matrix[i]); + } + free(matrix); + } +} + +static polyfit_error_t validate_input_arrays(const float* x, const float* y, + int32_t num_points) { + if (x == NULL || y == NULL) { + return POLYFIT_ERROR_NULL_POINTER; + } + + if (num_points <= 0) { + return POLYFIT_ERROR_INVALID_INPUT; + } + + // Check for NaN or infinite values + for (int32_t i = 0; i < num_points; i++) { + if (x[i] - x[i] != 0.0f || y[i] - y[i] != 0.0f) { // NaN and Inf check + return POLYFIT_ERROR_INVALID_INPUT; + } + } + + return POLYFIT_SUCCESS; +} + diff --git a/polyfit.h b/polyfit.h new file mode 100644 index 0000000..2944b83 --- /dev/null +++ b/polyfit.h @@ -0,0 +1,306 @@ +/** + ****************************************************************************** + * @file polyfit.h + * @brief Header file for polynomial fitting and evaluation library + * @version 1.0 + * @date 2025 + ****************************************************************************** + * @attention + * + * This library provides polynomial fitting using least squares regression + * and polynomial evaluation capabilities for embedded systems. + * + ****************************************************************************** + */ + +#ifndef POLYFIT_H_ +#define POLYFIT_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* CONSTANTS AND CONFIGURATION */ +/*============================================================================*/ + +/** @brief Default absolute threshold for near-zero values */ +#define POLYFIT_ABSOLUTE_THRESHOLD (1e-6f) + +/** @brief Default relative threshold for near-zero values */ +#define POLYFIT_RELATIVE_THRESHOLD (1e-6f) + +/** @brief Maximum supported polynomial degree */ +#define POLYFIT_MAX_DEGREE (10) + +/*============================================================================*/ +/* TYPE DEFINITIONS */ +/*============================================================================*/ + +/** + * @brief Error codes for polynomial operations + */ +typedef enum { + POLYFIT_SUCCESS = 0, /**< Operation successful */ + POLYFIT_ERROR_NULL_POINTER, /**< Null pointer passed */ + POLYFIT_ERROR_INVALID_DEGREE, /**< Invalid polynomial degree */ + POLYFIT_ERROR_MEMORY_ALLOC, /**< Memory allocation failed */ + POLYFIT_ERROR_SINGULAR_MATRIX, /**< Matrix is singular */ + POLYFIT_ERROR_INSUFFICIENT_POINTS, /**< Not enough data points */ + POLYFIT_ERROR_INVALID_INPUT /**< Invalid input parameters */ +} polyfit_error_t; + +/** + * @brief Structure to represent a polynomial + */ +typedef struct { + float* coefficients; /**< Array of polynomial coefficients */ + int32_t degree; /**< Degree of the polynomial */ + bool is_valid; /**< Flag indicating if polynomial is valid */ +} Polynomial; + +/** + * @brief Configuration structure for polynomial fitting + */ +typedef struct { + float absolute_threshold; /**< Absolute threshold for near-zero values */ + float relative_threshold; /**< Relative threshold for near-zero values */ + bool enable_pivot_check; /**< Enable pivot checking in Gaussian elimination */ +} polyfit_config_t; + +/*============================================================================*/ +/* FUNCTION DECLARATIONS */ +/*============================================================================*/ + +/** + * @brief Initialize a polynomial structure + * @param degree Degree of the polynomial (must be >= 0) + * @return Pointer to initialized Polynomial structure, or NULL on failure + * @note Caller is responsible for freeing the returned polynomial + */ +Polynomial* polyfit_init(int32_t degree); + +/** + * @brief Free memory allocated for a polynomial + * @param poly Pointer to the Polynomial structure to be freed + * @note Sets the polynomial to invalid state after freeing + */ +void polyfit_free(Polynomial* poly); + +/** + * @brief Perform least squares polynomial regression + * @param x Array of x values (must not be NULL) + * @param y Array of corresponding y values (must not be NULL) + * @param num_points Number of data points (must be > degree) + * @param degree Degree of the polynomial (must be >= 0) + * @param result_poly Pointer to store the resulting polynomial (must not be + * NULL) + * @return Error code indicating success or failure + */ +polyfit_error_t polyfit_least_squares(const float* x, const float* y, + int32_t num_points, int32_t degree, + Polynomial* result_poly); + +/** + * @brief Evaluate a polynomial at a given x value + * @param poly Pointer to the Polynomial structure (must not be NULL) + * @param x Value at which to evaluate the polynomial + * @param result Pointer to store the evaluation result (must not be NULL) + * @return Error code indicating success or failure + */ +polyfit_error_t polyfit_evaluate(const Polynomial* poly, float x, + float* result); + +/** + * @brief Get the maximum absolute magnitude among polynomial coefficients + * @param poly Pointer to the Polynomial structure (must not be NULL) + * @param max_magnitude Pointer to store the maximum magnitude (must not be + * NULL) + * @return Error code indicating success or failure + */ +polyfit_error_t polyfit_get_max_coefficient_magnitude(const Polynomial* poly, + float* max_magnitude); + +/** + * @brief Validate a polynomial structure + * @param poly Pointer to the Polynomial structure + * @return true if polynomial is valid, false otherwise + */ +bool polyfit_is_valid(const Polynomial* poly); + +/** + * @brief Get string representation of error code + * @param error Error code + * @return String representation of the error + */ +const char* polyfit_error_string(polyfit_error_t error); + +/*============================================================================*/ +/* CONVENIENCE FUNCTIONS */ +/*============================================================================*/ + +/** + * @brief Simplified polynomial fitting - allocates and fits in one call + * @param x Array of x values (must not be NULL) + * @param y Array of corresponding y values (must not be NULL) + * @param num_points Number of data points (must be > degree) + * @param degree Degree of the polynomial (must be >= 0) + * @param error Optional pointer to store error code (can be NULL) + * @return Pointer to fitted Polynomial structure, or NULL on failure + * @note Caller is responsible for freeing with polyfit_free() + * + * @example + * float x[] = {1, 2, 3, 4, 5}; + * float y[] = {2, 4, 6, 8, 10}; + * Polynomial *poly = polyfit(x, y, 5, 1, NULL); + * if (poly) { + * float result; + * polyfit_evaluate(poly, 6.0f, &result); + * polyfit_free(poly); + * } + */ +Polynomial* polyfit(const float* x, const float* y, int32_t num_points, + int32_t degree, polyfit_error_t* error); + +/** + * @brief Fit polynomial and evaluate at a single point + * @param x Array of x values for fitting (must not be NULL) + * @param y Array of y values for fitting (must not be NULL) + * @param num_points Number of data points (must be > degree) + * @param degree Degree of the polynomial (must be >= 0) + * @param eval_x Point at which to evaluate the fitted polynomial + * @param result Pointer to store the evaluation result (must not be NULL) + * @return Error code indicating success or failure + * @note This is a convenience function that doesn't require manual memory + * management + * + * @example + * float x[] = {1, 2, 3, 4, 5}; + * float y[] = {2, 4, 6, 8, 10}; + * float result; + * if (polyfit_eval_at(x, y, 5, 1, 6.0f, &result) == POLYFIT_SUCCESS) { + * printf("f(6) = %f\n", result); + * } + */ +polyfit_error_t polyfit_eval_at(const float* x, const float* y, + int32_t num_points, int32_t degree, + float eval_x, float* result); + +/** + * @brief Get polynomial coefficients as an array + * @param poly Pointer to the Polynomial structure (must not be NULL) + * @param coeffs Array to store coefficients (must not be NULL, size >= + * degree+1) + * @param size Size of the coeffs array + * @return Error code indicating success or failure + * @note Coefficients are in ascending order: coeffs[0] + coeffs[1]*x + + * coeffs[2]*x^2 + ... + * + * @example + * float coeffs[3]; + * if (polyfit_get_coefficients(poly, coeffs, 3) == POLYFIT_SUCCESS) { + * printf("Polynomial: %f + %f*x + %f*x^2\n", coeffs[0], coeffs[1], + * coeffs[2]); + * } + */ +polyfit_error_t polyfit_get_coefficients(const Polynomial* poly, float* coeffs, + int32_t size); + +/*============================================================================*/ +/* FIT QUALITY AND AUTO-DEGREE FUNCTIONS */ +/*============================================================================*/ + +/** + * @brief Compute residuals between polynomial predictions and actual values + * @param poly Pointer to fitted Polynomial (must not be NULL) + * @param x Array of x values (must not be NULL) + * @param y Array of y values (must not be NULL) + * @param num_points Number of data points + * @param residuals Output array of size >= num_points; stores (y_hat[i] - y[i]) + * @return Error code indicating success or failure + */ +polyfit_error_t polyfit_compute_residuals(const Polynomial* poly, + const float* x, const float* y, + int32_t num_points, + float* residuals); + +/** + * @brief Compute R-squared goodness-of-fit metric + * @param poly Pointer to fitted Polynomial (must not be NULL) + * @param x Array of x values (must not be NULL) + * @param y Array of y values (must not be NULL) + * @param num_points Number of data points + * @param r_squared Output pointer for R² value (0 to 1, higher is better) + * @return Error code indicating success or failure + */ +polyfit_error_t polyfit_r_squared(const Polynomial* poly, const float* x, + const float* y, int32_t num_points, + float* r_squared); + +/** + * @brief Automatically select the best polynomial degree using BIC + * + * Tries degrees 1 to max_degree, fits each polynomial, and selects the degree + * minimising the Bayesian Information Criterion: + * BIC = n * ln(RSS/n) + (d+1) * ln(n) + * + * BIC penalises complexity, preventing overfitting without cross-validation. + * + * @param x Array of x values (must not be NULL) + * @param y Array of y values (must not be NULL) + * @param num_points Number of data points (must be > max_degree) + * @param max_degree Maximum degree to evaluate (1 to POLYFIT_MAX_DEGREE) + * @param best_degree Output pointer for selected degree (must not be NULL) + * @param error Optional pointer to store error code (can be NULL) + * @return Pointer to the best-fit Polynomial, or NULL on failure + * @note Caller is responsible for freeing with polyfit_free() + * + * @example + * int32_t deg; + * Polynomial *poly = polyfit_best_degree(x, y, n, 5, °, NULL); + * if (poly) { + * printf("Best degree: %d\n", deg); + * polyfit_free(poly); + * } + */ +Polynomial* polyfit_best_degree(const float* x, const float* y, + int32_t num_points, int32_t max_degree, + int32_t* best_degree, polyfit_error_t* error); + +/*============================================================================*/ +/* UTILITY FUNCTIONS */ +/*============================================================================*/ + +/** + * @brief Calculate power of a base to an integer exponent + * @param base The base value + * @param exponent The exponent value + * @return Result of base raised to the power of exponent + * @note Handles special cases like 0^0 and negative exponents + */ +float polyfit_pow(float base, int32_t exponent); + +/** + * @brief Calculate absolute value of a floating-point number + * @param x The input floating-point number + * @return Absolute value of x + */ +float polyfit_fabs(float x); + +/** + * @brief Check if a floating-point number is nearly zero + * @param value The value to check + * @param threshold The threshold for comparison + * @return true if value is nearly zero, false otherwise + */ +bool polyfit_is_nearly_zero(float value, float threshold); + +#ifdef __cplusplus +} +#endif + +#endif /* POLYFIT_H_ */ \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 172d294..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_subdirectory(utility) -add_subdirectory(lib) -add_subdirectory(app) diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt deleted file mode 100644 index 23c085b..0000000 --- a/src/app/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_executable(APP) -target_sources(APP PRIVATE demo.c) -target_link_libraries(APP PRIVATE example utilities) -target_linker_map(APP) - -# Apply unconditional private flags here -list(APPEND APP_private_compile_flags - "-Wno-unknown-pragmas" -) -apply_supported_compiler_flags(C APP PRIVATE APP_private_compile_flags) diff --git a/src/app/demo.c b/src/app/demo.c deleted file mode 100644 index 71b406c..0000000 --- a/src/app/demo.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include - -void basicDemo(void); - -int main(void) -{ - basicDemo(); - return (EXIT_SUCCESS); -} - -/** - * @brief Demonstrates modelling an x^2 parabola using the library. - * - * This example illustrates the four main steps involved in using the library to fit a polynomial to - * data and evaluate it. - */ -void basicDemo(void) -{ - /** - * @brief Initializes the polynomial with a given degree. - * - * This function allocates memory and sets up the internal state of the polynomial - * object. The degree parameter specifies the highest power of the polynomial. - * - * @param degree The degree of the polynomial. - * - * @return A pointer to the newly created polynomial object, or NULL on failure. - */ - int32_t degree = 3; - Polynomial* poly = initPolynomial(degree); - - /** - * @brief Fits the polynomial coefficients to a given dataset. - * - * This function uses the least squares method to fit the polynomial coefficients - * to a set of sample points provided in the xData and yData arrays. - * - * @param xData An array of x-coordinates of the sample points. - * @param yData An array of y-coordinates of the sample points. - * @param numSamples The number of samples in the dataset. - * @param degree The degree of the polynomial. - * @param poly The polynomial object to fit. - */ - float xData[] = {0, 2, 4, 5}; - float yData[] = {0, 8, 64, 125}; - - int32_t numXSamples = (int32_t)(sizeof(xData) / sizeof(xData[0])); - int32_t numYSamples = (int32_t)(sizeof(yData) / sizeof(yData[0])); - if(numXSamples == numYSamples) - { - leastSquaresPolynomialRegression(xData, yData, numXSamples, degree, poly); - } - else - { - // Handle error gracefully - exit(EXIT_FAILURE); - } - - /** - * @brief Evaluates the polynomial at a given x-value. - * - * This function calculates the corresponding y-value for a given x-coordinate - * based on the fitted polynomial coefficients. - * - * @param poly The fitted polynomial object. - * @param x The x-coordinate to evaluate. - * - * @return The calculated y-value. - */ - printf("Testing polynomial for various x values:\n"); - printf("| %-10s | %-10s |\n", "x", "y (y=x^2)"); - printf("|------------|------------|\n"); - - for(float x = -10; x <= 10; x += 1) - { - float y = evaluatePolynomial(poly, x); - printf("| %-10.2f | %-10.2f |\n", x, y); - } - - /** - * @brief Frees the memory allocated for the polynomial object. - * - * This function deallocates the memory used by the polynomial object to - * prevent memory leaks. - * - * @param poly The polynomial object to free. - */ - freePolynomial(poly); -} diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt deleted file mode 100644 index 921e5aa..0000000 --- a/src/lib/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# Libraries live here -# -# This are larger modules with a cohesive set of features used to accomplish some -# purpose, e.g. WolfSSL or liblz4. Smaller, single-purpose modules should live in utilities. - -# Save the library directory path for use with our `add_library` call below -set(LIBRARY_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}) - -# All targets in the lib tree should be included with a directory prefix: -# #include -# To accomplish this, we automatically set `target_include_directories` for library -# targets so this scheme can be used. -# -# Library targets themselves should NOT set public/interface includes within the library tree -function(add_library target) - # Forward all arguments to the orginal add_library - _add_library(${target} ${ARGN}) - # Ensure this directory is included as an interface include - target_include_directories(${target} INTERFACE ${LIBRARY_ROOT_DIR}) -endfunction() - -############# -# Libraries # -############# - -add_subdirectory(polyfit) diff --git a/src/lib/polyfit/CMakeLists.txt b/src/lib/polyfit/CMakeLists.txt deleted file mode 100644 index 1488e28..0000000 --- a/src/lib/polyfit/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_library(polyfit) -target_sources(polyfit PRIVATE polyfit.c) diff --git a/src/lib/polyfit/polyfit.c b/src/lib/polyfit/polyfit.c deleted file mode 100644 index d602082..0000000 --- a/src/lib/polyfit/polyfit.c +++ /dev/null @@ -1,269 +0,0 @@ -/** - ****************************************************************************** - * @file polyfit.c - * @brief Source file for fitting polynomials to datasets. - ****************************************************************************** - * @attention - * - * This file is heavily dependent on dynamic memory allocation, ew. - * I had to develop this quickly over a day and test on the host machine. - * Malloc was faster to develop with, but I know it is not ideal for embedded. - * Will refactor to static alloc when I have the time ಥ_ಥ - * - ****************************************************************************** - */ - -#include "polyfit.h" - -/** - * @brief Initialise a polynomial and return a pointer to it. - * - * @param degree Degree of the polynomial. - * @return Pointer to the Initialised polynomial. - */ -Polynomial *initPolynomial(int32_t degree) { - Polynomial *poly = (Polynomial *)malloc(sizeof(Polynomial)); - - // Check if memory allocation was successful - if (poly == NULL) { - // Error: Memory allocation failed for polynomial structure. - exit(EXIT_FAILURE); // or handle the error in a way suitable for your - // application - } - - poly->coefficients = (float *)malloc((degree + 1) * sizeof(float)); - - // Check if memory allocation was successful - if (poly->coefficients == NULL) { - // Error: Memory allocation failed for polynomial coefficients - free(poly); // free the previously allocated memory for the structure - exit(EXIT_FAILURE); // or handle the error in a way suitable for your - // application - } - - // Init coefficients to zero - for (int32_t i = 0; i <= degree; ++i) { - poly->coefficients[i] = 0.0; - } - - poly->degree = degree; - return (poly); -} - -/** - * @brief Free memory allocated for a polynomial. - * - * @param poly Pointer to the polynomial to be freed. - */ -void freePolynomial(Polynomial *poly) { free(poly->coefficients); } - -/** - * @brief Perform Gaussian elimination to solve a system of linear equations. - * - * @param A Coefficient matrix. - * @param B Right-hand side vector. - * @param x Solution vector. - * @param n Size of the system. - */ -void gaussianElimination(float **A, float *B, float *x, int32_t n) { - for (int32_t i = 0; i < n; ++i) { - // Pivot - int32_t max = i; - for (int32_t j = i + 1; j < n; ++j) { - if (tinyFabs(A[j][i]) > tinyFabs(A[max][i])) { - max = j; - } - } - - // Swap rows i and max - float *temp = A[i]; - A[i] = A[max]; - A[max] = temp; - float t = B[i]; - B[i] = B[max]; - B[max] = t; - - // Forward elimination - for (int32_t j = i + 1; j < n; ++j) { - float f = A[j][i] / A[i][i]; - for (int32_t k = i; k < n; ++k) { - A[j][k] -= A[i][k] * f; - } - B[j] -= B[i] * f; - } - } - - // Backward substitution - for (int32_t i = n - 1; i >= 0; --i) { - for (int32_t j = i + 1; j < n; ++j) { - B[i] -= A[i][j] * x[j]; - } - x[i] = B[i] / A[i][i]; - } -} - -/** - * @brief Perform least squares polynomial regression. - * - * @param x Array of x values. - * @param y Array of corresponding y values. - * @param numPoints Number of data points. - * @param degree Degree of the polynomial regression. - * @param resultPoly Pointer to store the result polynomial. - */ -void leastSquaresPolynomialRegression(const float *x, const float *y, - int32_t numPoints, int32_t degree, - Polynomial *resultPoly) { - // Allocate matrices A and B - float **A = (float **)malloc((degree + 1) * sizeof(float *)); - for (int32_t i = 0; i <= degree; ++i) { - A[i] = (float *)malloc((degree + 1) * sizeof(float)); - } - float *B = (float *)malloc((degree + 1) * sizeof(float)); - - // Initialise matrices A and B - for (int32_t i = 0; i <= degree; ++i) { - B[i] = 0.0; - for (int32_t j = 0; j <= degree; ++j) { - A[i][j] = 0.0; - for (int32_t k = 0; k < numPoints; ++k) { - A[i][j] += tinyPow(x[k], i + j); - } - } - for (int32_t k = 0; k < numPoints; ++k) { - B[i] += y[k] * tinyPow(x[k], i); - } - } - - // Solve the system of linear equations (Ax = B) for coefficients - gaussianElimination(A, B, resultPoly->coefficients, degree + 1); - - // Free allocated memory for matrices - for (int32_t i = 0; i <= degree; ++i) { - free(A[i]); - } - free(A); - free(B); -} - -/** - * @brief Evaluate the polynomial at a given x value. - * - * @param poly Pointer to the polynomial. - * @param x Value at which to evaluate the polynomial. - * @return Result of the polynomial evaluation. - */ -float evaluatePolynomial(const Polynomial *poly, float x) { - if (poly == NULL || poly->coefficients == NULL) { - return 0.0f; - } - - float result = 0.0; - - for (int32_t i = 0; i <= poly->degree; ++i) { - result += poly->coefficients[i] * tinyPow(x, i); - } - - // Apply a combination of relative and absolute thresholds - // Absolute threshold to consider a value negligible - float absoluteThreshold = 1e-6; - // Relative threshold relative to coefficient magnitudes - float relativeThreshold = 1e-6; - - // If the result is close to zero, set it to zero - if (tinyFabs(result) < - relativeThreshold * - getMaxCoefficientMagnitude(poly->coefficients, poly->degree) || - tinyFabs(result) < absoluteThreshold) { - result = 0.0f; - } - - return (result); -} - -/** - * @brief Get the maximum absolute magnitude among the polynomial coefficients. - * - * @param coefficients Array of polynomial coefficients. - * @param degree Degree of the polynomial. - * @return Maximum absolute magnitude among the coefficients. - */ -float getMaxCoefficientMagnitude(const float *coefficients, int32_t degree) { - if (coefficients == NULL) { - return 0.0f; - } - - float maxMagnitude = 0.0; - - for (int32_t i = 0; i <= degree; ++i) { - float magnitude = tinyFabs(coefficients[i]); - if (magnitude > maxMagnitude) { - maxMagnitude = magnitude; - } - } - - return (maxMagnitude); -} - -/** - * @brief Function to calculate the power of a base to an exponent. - * @brief This is to avoid having to link the MASSIVE math.h library. - * @param base The base value (float). - * @param exponent The exponent value (signed 32-bit integer). - * @return Result of base raised to the power of exponent. - */ -float tinyPow(float base, int32_t exponent) { - // Check for special cases - if (base == 0.0f) { - if (exponent == 0) { - return 1.0f; // 0^0 is considered 1 by convention - } else if (exponent < 0) { - // Handling 0 ^ negative_exponent is undefined, return an error value or - // NaN as needed - return (0.0f); // Adjust this according to your specific requirements - } - } - - // Initialise result - float result = 1.0f; - - // Determine the positive or negative exponent - int32_t absExponent = exponent > 0 ? exponent : -exponent; - - // Calculate power using binary exponentiation for efficiency - while (absExponent > 0) { - if (absExponent % 2 == 1) { - result *= base; - } - base *= base; - absExponent /= 2; - } - - // Adjust result for negative exponent - if (exponent < 0) { - result = 1.0f / result; - } - - return (result); -} - -/** - * @brief Calculate the absolute value of a floating-point number. - * @param x The input floating-point number. - * @return Absolute value of x. - */ -float tinyFabs(float x) { - // Handle NaN (Not-a-Number) - if (!(x == x)) { - // Return NaN if x is NaN - return (x); - } - - // Handle negative zero - if (x == 0.0f && *((uint32_t *)&x) & 0x80000000) { - // Return positive zero if x is negative zero - return (0.0f); - } - - return ((x < 0.0f) ? -x : x); -} diff --git a/src/lib/polyfit/polyfit.h b/src/lib/polyfit/polyfit.h deleted file mode 100644 index 866cf2f..0000000 --- a/src/lib/polyfit/polyfit.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - ****************************************************************************** - * @file polyfit.h - * @brief Header file for fitting polynomials to datasets. - ****************************************************************************** - */ - -#ifndef INC_POLYFIT_H_ -#define INC_POLYFIT_H_ - -#include -#include -#include - -/** - * @brief Structure to hold the polynomial coefficients - */ -typedef struct { - float *coefficients; /**< Array of coefficients */ - int32_t degree; /**< Degree of the polynomial */ -} Polynomial; - -/** - * @brief Function to initialise a polynomial - * @param degree Degree of the polynomial - * @return Pointer to initialised Polynomial structure - */ -Polynomial *initPolynomial(int32_t degree); - -/** - * @brief Function to free memory allocated for a polynomial - * @param poly Pointer to the Polynomial structure to be freed - */ -void freePolynomial(Polynomial *poly); - -/** - * @brief Function to perform Gaussian elimination - * @param A Matrix of coefficients - * @param B Array of constants - * @param x Array to store the solution - * @param n Size of the system (number of equations) - */ -void gaussianElimination(float **A, float *B, float *x, int32_t n); - -/** - * @brief Function to perform least squares polynomial regression - * @param x Array of x values - * @param y Array of corresponding y values - * @param numPoints Number of data points - * @param degree Degree of the polynomial - * @param resultPoly Pointer to store the resulting polynomial - */ -void leastSquaresPolynomialRegression(const float *x, const float *y, - int32_t numPoints, int32_t degree, - Polynomial *resultPoly); - -/** - * @brief Function to evaluate the polynomial at a given x value - * @param poly Pointer to the Polynomial structure - * @param x Value at which the polynomial is evaluated - * @return Result of the polynomial evaluation - */ -float evaluatePolynomial(const Polynomial *poly, float x); - -/** - * @brief Get the maximum absolute magnitude among the polynomial coefficients. - * - * @param coefficients Array of polynomial coefficients. - * @param degree Degree of the polynomial. - * @return Maximum absolute magnitude among the coefficients. - */ -float getMaxCoefficientMagnitude(const float *coefficients, int32_t degree); - - -/** - * @brief Function to calculate the power of a base to an exponent. - * @brief This is to avoid having to link the MASSIVE math.h library. - * @param base The base value (float). - * @param exponent The exponent value (signed 32-bit integer). - * @return Result of base raised to the power of exponent. - */ -float tinyPow(float base, int32_t exponent); - -/** - * @brief Calculate the absolute value of a floating-point number. - * @param x The input floating-point number. - * @return Absolute value of x. - */ -float tinyFabs(float x); - -#endif /* INC_POLYFIT_H_ */ diff --git a/src/utility/CMakeLists.txt b/src/utility/CMakeLists.txt deleted file mode 100644 index 31ff70d..0000000 --- a/src/utility/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Utilities live here -# (standalone modules with singular functionality implemented in a standalone manner) -# -# Utility modules are expected to live in subdirectories of this folder, so they -# are included via `#include -# -# The default build structure is for a header-only libraries. -# -# If you want to add source files, remove the `INTERFACE` option from `add_library`. -# And make the INTERFACE option in `target_include_directories` PUBLIC. -# Then, you can use `add_subdirectory` and call `target_sources(utilities PRIVATE ...)` -# to add files to the library. - -add_library(utilities INTERFACE) -target_include_directories(utilities INTERFACE .) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index 3f2adac..0000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -if(PROJECTVARNAME_TESTING_IS_ENABLED) - ################ - # CMocka Tests # - ################ - add_executable(MYPROJECT_tests) - target_include_directories(MYPROJECT_tests PRIVATE .) - target_link_libraries(MYPROJECT_tests PRIVATE cmocka_dep) - target_sources(MYPROJECT_tests PRIVATE - main.c - test_suite.c - ) - target_linker_map(MYPROJECT_tests) - - list(APPEND desired_MYPROJECT_test_flags - "-Wno-unused-parameter" - ) - apply_supported_compiler_flags(C MYPROJECT_tests PRIVATE desired_MYPROJECT_test_flags) - - # This registers the test and defines testing targets - register_cmocka_test(MYPROJECT.Test MYPROJECT_tests) - - ################ - # Catch2 Tests # - ################ - add_executable(MYPROJECT_catch_tests) - target_link_libraries(MYPROJECT_catch_tests PRIVATE catch2_dep) - target_sources(MYPROJECT_catch_tests PRIVATE - catch2_test_case.cpp - ) - - register_catch2_test(MYPROJECT.Catch2.Test MYPROJECT_catch_tests) -endif(PROJECTVARNAME_TESTING_IS_ENABLED) diff --git a/test/README.md b/test/README.md deleted file mode 100644 index 18918e7..0000000 --- a/test/README.md +++ /dev/null @@ -1 +0,0 @@ -The `test` folder contains tests and testing frameworks. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..56c87ce --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,17 @@ +include(FetchContent) + +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz + DOWNLOAD_EXTRACT_TIMESTAMP TRUE +) + +# Prevent overriding the parent project's compiler/linker settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +add_executable(test_polyfit test_polyfit.cpp) +target_link_libraries(test_polyfit PRIVATE polyfit GTest::gtest_main) + +include(GoogleTest) +gtest_discover_tests(test_polyfit) diff --git a/tests/test_polyfit.cpp b/tests/test_polyfit.cpp new file mode 100644 index 0000000..dd79372 --- /dev/null +++ b/tests/test_polyfit.cpp @@ -0,0 +1,508 @@ +extern "C" { +#include "polyfit.h" +} + +#include +#include + +/*============================================================================*/ +/* SHARED TEST DATA */ +/*============================================================================*/ + +// y = 2x + 1 over 5 points +static const float kLinX[] = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f}; +static const float kLinY[] = {1.0f, 3.0f, 5.0f, 7.0f, 9.0f}; +static const int kLinN = 5; + +// y = x^2 over 9 points +static const float kQuadX[] = {-3.0f, -2.0f, -1.0f, 0.0f, 1.0f, + 2.0f, 3.0f, 4.0f, 5.0f}; +static const float kQuadY[] = { 9.0f, 4.0f, 1.0f, 0.0f, 1.0f, + 4.0f, 9.0f, 16.0f, 25.0f}; +static const int kQuadN = 9; + +/*============================================================================*/ +/* INIT / FREE */ +/*============================================================================*/ + +TEST(PolyfitInit, ValidDegrees) { + Polynomial *p = polyfit_init(0); + ASSERT_NE(p, nullptr); + EXPECT_EQ(p->degree, 0); + EXPECT_TRUE(p->is_valid); + polyfit_free(p); + + p = polyfit_init(1); + ASSERT_NE(p, nullptr); + EXPECT_EQ(p->degree, 1); + polyfit_free(p); + + p = polyfit_init(POLYFIT_MAX_DEGREE); + ASSERT_NE(p, nullptr); + EXPECT_EQ(p->degree, POLYFIT_MAX_DEGREE); + polyfit_free(p); +} + +TEST(PolyfitInit, NegativeDegreeReturnsNull) { + EXPECT_EQ(polyfit_init(-1), nullptr); +} + +TEST(PolyfitInit, ExceedsMaxDegreeReturnsNull) { + EXPECT_EQ(polyfit_init(POLYFIT_MAX_DEGREE + 1), nullptr); +} + +TEST(PolyfitFree, NullIsSafe) { + EXPECT_NO_THROW(polyfit_free(nullptr)); +} + +/*============================================================================*/ +/* IS VALID */ +/*============================================================================*/ + +TEST(PolyfitIsValid, Null) { + EXPECT_FALSE(polyfit_is_valid(nullptr)); +} + +TEST(PolyfitIsValid, ValidPolyAfterInit) { + Polynomial *p = polyfit_init(2); + ASSERT_NE(p, nullptr); + EXPECT_TRUE(polyfit_is_valid(p)); + polyfit_free(p); +} + +TEST(PolyfitIsValid, NullCoefficientsIsInvalid) { + Polynomial p; + p.coefficients = nullptr; + p.degree = 1; + p.is_valid = true; + EXPECT_FALSE(polyfit_is_valid(&p)); +} + +/*============================================================================*/ +/* ERROR STRINGS */ +/*============================================================================*/ + +TEST(PolyfitErrorString, AllCodesReturnNonNull) { + EXPECT_STREQ(polyfit_error_string(POLYFIT_SUCCESS), "Success"); + EXPECT_NE(polyfit_error_string(POLYFIT_ERROR_NULL_POINTER), nullptr); + EXPECT_NE(polyfit_error_string(POLYFIT_ERROR_INVALID_DEGREE), nullptr); + EXPECT_NE(polyfit_error_string(POLYFIT_ERROR_MEMORY_ALLOC), nullptr); + EXPECT_NE(polyfit_error_string(POLYFIT_ERROR_SINGULAR_MATRIX), nullptr); + EXPECT_NE(polyfit_error_string(POLYFIT_ERROR_INSUFFICIENT_POINTS), nullptr); + EXPECT_NE(polyfit_error_string(POLYFIT_ERROR_INVALID_INPUT), nullptr); +} + +TEST(PolyfitErrorString, UnknownCodeReturnsNonNull) { + EXPECT_NE(polyfit_error_string((polyfit_error_t)999), nullptr); +} + +/*============================================================================*/ +/* LEAST SQUARES CORE */ +/*============================================================================*/ + +TEST(PolyfitLeastSquares, LinearFit) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_least_squares(kLinX, kLinY, kLinN, 1, p), POLYFIT_SUCCESS); + // y = 1 + 2x → coeffs[0]=1, coeffs[1]=2 + EXPECT_NEAR(p->coefficients[0], 1.0f, 1e-4f); + EXPECT_NEAR(p->coefficients[1], 2.0f, 1e-4f); + polyfit_free(p); +} + +TEST(PolyfitLeastSquares, QuadraticFit) { + Polynomial *p = polyfit_init(2); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_least_squares(kQuadX, kQuadY, kQuadN, 2, p), POLYFIT_SUCCESS); + // y = x^2 → coeffs[0]=0, coeffs[1]=0, coeffs[2]=1 + EXPECT_NEAR(p->coefficients[0], 0.0f, 1e-4f); + EXPECT_NEAR(p->coefficients[1], 0.0f, 1e-4f); + EXPECT_NEAR(p->coefficients[2], 1.0f, 1e-4f); + polyfit_free(p); +} + +TEST(PolyfitLeastSquares, NullXReturnsError) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_least_squares(nullptr, kLinY, kLinN, 1, p), + POLYFIT_ERROR_NULL_POINTER); + polyfit_free(p); +} + +TEST(PolyfitLeastSquares, NullYReturnsError) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_least_squares(kLinX, nullptr, kLinN, 1, p), + POLYFIT_ERROR_NULL_POINTER); + polyfit_free(p); +} + +TEST(PolyfitLeastSquares, NullResultReturnsError) { + EXPECT_EQ(polyfit_least_squares(kLinX, kLinY, kLinN, 1, nullptr), + POLYFIT_ERROR_NULL_POINTER); +} + +TEST(PolyfitLeastSquares, InsufficientPoints) { + Polynomial *p = polyfit_init(2); + ASSERT_NE(p, nullptr); + // num_points must be > degree; 2 points for degree 2 is not enough + EXPECT_EQ(polyfit_least_squares(kLinX, kLinY, 2, 2, p), + POLYFIT_ERROR_INSUFFICIENT_POINTS); + polyfit_free(p); +} + +TEST(PolyfitLeastSquares, NegativeDegreeReturnsError) { + Polynomial *p = polyfit_init(0); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_least_squares(kLinX, kLinY, kLinN, -1, p), + POLYFIT_ERROR_INVALID_DEGREE); + polyfit_free(p); +} + +TEST(PolyfitLeastSquares, ExceedsMaxDegreeReturnsError) { + Polynomial *p = polyfit_init(0); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_least_squares(kLinX, kLinY, kLinN, POLYFIT_MAX_DEGREE + 1, p), + POLYFIT_ERROR_INVALID_DEGREE); + polyfit_free(p); +} + +TEST(PolyfitLeastSquares, NaNInputRejected) { + float xi[] = {1.0f, 2.0f, 3.0f}; + float yi[] = {0.0f / 0.0f, 2.0f, 3.0f}; // NaN + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_least_squares(xi, yi, 3, 1, p), POLYFIT_ERROR_INVALID_INPUT); + polyfit_free(p); +} + +TEST(PolyfitLeastSquares, InfInputRejected) { + float xi[] = {1.0f, 2.0f, 3.0f}; + float yi[] = {1.0f / 0.0f, 2.0f, 3.0f}; // +Inf + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_least_squares(xi, yi, 3, 1, p), POLYFIT_ERROR_INVALID_INPUT); + polyfit_free(p); +} + +/*============================================================================*/ +/* EVALUATE */ +/*============================================================================*/ + +TEST(PolyfitEvaluate, LinearAtKnownPoints) { + Polynomial *p = polyfit(kLinX, kLinY, kLinN, 1, nullptr); + ASSERT_NE(p, nullptr); + + float result; + EXPECT_EQ(polyfit_evaluate(p, 0.0f, &result), POLYFIT_SUCCESS); + EXPECT_NEAR(result, 1.0f, 1e-4f); + EXPECT_EQ(polyfit_evaluate(p, 4.0f, &result), POLYFIT_SUCCESS); + EXPECT_NEAR(result, 9.0f, 1e-4f); + + polyfit_free(p); +} + +TEST(PolyfitEvaluate, NullPolyReturnsError) { + float result; + EXPECT_EQ(polyfit_evaluate(nullptr, 1.0f, &result), POLYFIT_ERROR_NULL_POINTER); +} + +TEST(PolyfitEvaluate, NullResultReturnsError) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_evaluate(p, 1.0f, nullptr), POLYFIT_ERROR_NULL_POINTER); + polyfit_free(p); +} + +TEST(PolyfitEvaluate, SmallLegitimateValueNotSnappedToZero) { + // y = 5e-7 * x — values well below the old 1e-6 absolute snap threshold + float xs[] = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f}; + float ys[] = {0.0f, 5e-7f, 10e-7f, 15e-7f, 20e-7f}; + Polynomial *p = polyfit(xs, ys, 5, 1, nullptr); + ASSERT_NE(p, nullptr); + + float result; + EXPECT_EQ(polyfit_evaluate(p, 1.0f, &result), POLYFIT_SUCCESS); + EXPECT_NEAR(result, 5e-7f, 1e-8f); // must NOT be zero + + polyfit_free(p); +} + +/*============================================================================*/ +/* CONVENIENCE FUNCTIONS */ +/*============================================================================*/ + +TEST(PolyfitConvenience, PolyfitLinearFit) { + polyfit_error_t err; + Polynomial *p = polyfit(kLinX, kLinY, kLinN, 1, &err); + ASSERT_NE(p, nullptr); + EXPECT_EQ(err, POLYFIT_SUCCESS); + EXPECT_NEAR(p->coefficients[0], 1.0f, 1e-4f); + EXPECT_NEAR(p->coefficients[1], 2.0f, 1e-4f); + polyfit_free(p); +} + +TEST(PolyfitConvenience, PolyfitReturnsNullOnNullInput) { + polyfit_error_t err; + Polynomial *p = polyfit(nullptr, kLinY, kLinN, 1, &err); + EXPECT_EQ(p, nullptr); + EXPECT_EQ(err, POLYFIT_ERROR_NULL_POINTER); +} + +TEST(PolyfitConvenience, EvalAtQuadratic) { + float result; + EXPECT_EQ(polyfit_eval_at(kQuadX, kQuadY, kQuadN, 2, 4.0f, &result), + POLYFIT_SUCCESS); + EXPECT_NEAR(result, 16.0f, 1e-3f); +} + +TEST(PolyfitConvenience, EvalAtNullResultReturnsError) { + EXPECT_EQ(polyfit_eval_at(kQuadX, kQuadY, kQuadN, 2, 4.0f, nullptr), + POLYFIT_ERROR_NULL_POINTER); +} + +TEST(PolyfitConvenience, GetCoefficients) { + Polynomial *p = polyfit(kLinX, kLinY, kLinN, 1, nullptr); + ASSERT_NE(p, nullptr); + + float coeffs[2]; + EXPECT_EQ(polyfit_get_coefficients(p, coeffs, 2), POLYFIT_SUCCESS); + EXPECT_NEAR(coeffs[0], 1.0f, 1e-4f); + EXPECT_NEAR(coeffs[1], 2.0f, 1e-4f); + + polyfit_free(p); +} + +TEST(PolyfitConvenience, GetCoefficientsBufferTooSmall) { + Polynomial *p = polyfit(kLinX, kLinY, kLinN, 1, nullptr); + ASSERT_NE(p, nullptr); + + float coeffs[1]; // degree=1 needs 2 elements + EXPECT_EQ(polyfit_get_coefficients(p, coeffs, 1), POLYFIT_ERROR_INVALID_INPUT); + + polyfit_free(p); +} + +/*============================================================================*/ +/* RESIDUALS */ +/*============================================================================*/ + +TEST(PolyfitResiduals, PerfectFitNearZero) { + Polynomial *p = polyfit(kQuadX, kQuadY, kQuadN, 2, nullptr); + ASSERT_NE(p, nullptr); + + float residuals[9]; + EXPECT_EQ(polyfit_compute_residuals(p, kQuadX, kQuadY, kQuadN, residuals), + POLYFIT_SUCCESS); + for (int i = 0; i < kQuadN; i++) { + EXPECT_NEAR(residuals[i], 0.0f, 1e-3f) << "residuals[" << i << "]"; + } + + polyfit_free(p); +} + +TEST(PolyfitResiduals, NullPolyReturnsError) { + float residuals[5]; + EXPECT_EQ(polyfit_compute_residuals(nullptr, kLinX, kLinY, kLinN, residuals), + POLYFIT_ERROR_NULL_POINTER); +} + +TEST(PolyfitResiduals, NullXReturnsError) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + float residuals[5]; + EXPECT_EQ(polyfit_compute_residuals(p, nullptr, kLinY, kLinN, residuals), + POLYFIT_ERROR_NULL_POINTER); + polyfit_free(p); +} + +TEST(PolyfitResiduals, NullYReturnsError) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + float residuals[5]; + EXPECT_EQ(polyfit_compute_residuals(p, kLinX, nullptr, kLinN, residuals), + POLYFIT_ERROR_NULL_POINTER); + polyfit_free(p); +} + +TEST(PolyfitResiduals, NullResidualsOutputReturnsError) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_compute_residuals(p, kLinX, kLinY, kLinN, nullptr), + POLYFIT_ERROR_NULL_POINTER); + polyfit_free(p); +} + +/*============================================================================*/ +/* R-SQUARED */ +/*============================================================================*/ + +TEST(PolyfitRSquared, PerfectFitIsOne) { + Polynomial *p = polyfit(kQuadX, kQuadY, kQuadN, 2, nullptr); + ASSERT_NE(p, nullptr); + + float r2; + EXPECT_EQ(polyfit_r_squared(p, kQuadX, kQuadY, kQuadN, &r2), POLYFIT_SUCCESS); + EXPECT_NEAR(r2, 1.0f, 1e-5f); + + polyfit_free(p); +} + +TEST(PolyfitRSquared, WrongDegreeGivesLowerScore) { + // Fit degree-1 to quadratic data — R² should be well below 1 + Polynomial *p = polyfit(kQuadX, kQuadY, kQuadN, 1, nullptr); + ASSERT_NE(p, nullptr); + + float r2; + EXPECT_EQ(polyfit_r_squared(p, kQuadX, kQuadY, kQuadN, &r2), POLYFIT_SUCCESS); + EXPECT_LT(r2, 0.99f); + + polyfit_free(p); +} + +TEST(PolyfitRSquared, NullPolyReturnsError) { + float r2; + EXPECT_EQ(polyfit_r_squared(nullptr, kLinX, kLinY, kLinN, &r2), + POLYFIT_ERROR_NULL_POINTER); +} + +TEST(PolyfitRSquared, NullXReturnsError) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + float r2; + EXPECT_EQ(polyfit_r_squared(p, nullptr, kLinY, kLinN, &r2), + POLYFIT_ERROR_NULL_POINTER); + polyfit_free(p); +} + +TEST(PolyfitRSquared, NullYReturnsError) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + float r2; + EXPECT_EQ(polyfit_r_squared(p, kLinX, nullptr, kLinN, &r2), + POLYFIT_ERROR_NULL_POINTER); + polyfit_free(p); +} + +TEST(PolyfitRSquared, NullOutputReturnsError) { + Polynomial *p = polyfit_init(1); + ASSERT_NE(p, nullptr); + EXPECT_EQ(polyfit_r_squared(p, kLinX, kLinY, kLinN, nullptr), + POLYFIT_ERROR_NULL_POINTER); + polyfit_free(p); +} + +/*============================================================================*/ +/* BEST DEGREE AUTO-SELECTION */ +/*============================================================================*/ + +TEST(PolyfitBestDegree, SelectsLinearForLinearData) { + int32_t deg; + Polynomial *p = polyfit_best_degree(kLinX, kLinY, kLinN, 3, °, nullptr); + ASSERT_NE(p, nullptr); + EXPECT_EQ(deg, 1); + polyfit_free(p); +} + +TEST(PolyfitBestDegree, SelectsQuadraticForQuadraticData) { + int32_t deg; + Polynomial *p = polyfit_best_degree(kQuadX, kQuadY, kQuadN, 5, °, nullptr); + ASSERT_NE(p, nullptr); + EXPECT_EQ(deg, 2); + polyfit_free(p); +} + +TEST(PolyfitBestDegree, ReturnedPolyEvaluatesCorrectly) { + int32_t deg; + Polynomial *p = polyfit_best_degree(kQuadX, kQuadY, kQuadN, 4, °, nullptr); + ASSERT_NE(p, nullptr); + + float result; + EXPECT_EQ(polyfit_evaluate(p, 4.0f, &result), POLYFIT_SUCCESS); + EXPECT_NEAR(result, 16.0f, 1e-2f); + + polyfit_free(p); +} + +TEST(PolyfitBestDegree, NullXReturnsError) { + int32_t deg; + polyfit_error_t err; + EXPECT_EQ(polyfit_best_degree(nullptr, kQuadY, kQuadN, 4, °, &err), nullptr); + EXPECT_EQ(err, POLYFIT_ERROR_NULL_POINTER); +} + +TEST(PolyfitBestDegree, NullYReturnsError) { + int32_t deg; + polyfit_error_t err; + EXPECT_EQ(polyfit_best_degree(kQuadX, nullptr, kQuadN, 4, °, &err), nullptr); + EXPECT_EQ(err, POLYFIT_ERROR_NULL_POINTER); +} + +TEST(PolyfitBestDegree, NullBestDegreeOutputReturnsError) { + polyfit_error_t err; + EXPECT_EQ(polyfit_best_degree(kQuadX, kQuadY, kQuadN, 4, nullptr, &err), nullptr); + EXPECT_EQ(err, POLYFIT_ERROR_NULL_POINTER); +} + +TEST(PolyfitBestDegree, InsufficientPoints) { + // 3 points but max_degree=5 requires at least 6 points + float xi[] = {0.0f, 1.0f, 2.0f}; + float yi[] = {1.0f, 2.0f, 4.0f}; + int32_t deg; + polyfit_error_t err; + Polynomial *p = polyfit_best_degree(xi, yi, 3, 5, °, &err); + EXPECT_EQ(p, nullptr); + EXPECT_EQ(err, POLYFIT_ERROR_INSUFFICIENT_POINTS); +} + +/*============================================================================*/ +/* UTILITY FUNCTIONS */ +/*============================================================================*/ + +TEST(PolyfitPow, ZeroExponent) { + EXPECT_FLOAT_EQ(polyfit_pow(5.0f, 0), 1.0f); + EXPECT_FLOAT_EQ(polyfit_pow(0.0f, 0), 1.0f); // 0^0 = 1 by convention +} + +TEST(PolyfitPow, ZeroBase) { + EXPECT_FLOAT_EQ(polyfit_pow(0.0f, 3), 0.0f); +} + +TEST(PolyfitPow, OneBase) { + EXPECT_FLOAT_EQ(polyfit_pow(1.0f, 99), 1.0f); +} + +TEST(PolyfitPow, NegativeOneBase) { + EXPECT_FLOAT_EQ(polyfit_pow(-1.0f, 2), 1.0f); // even exponent + EXPECT_FLOAT_EQ(polyfit_pow(-1.0f, 3), -1.0f); // odd exponent +} + +TEST(PolyfitPow, PositiveExponents) { + EXPECT_NEAR(polyfit_pow(2.0f, 3), 8.0f, 1e-6f); + EXPECT_NEAR(polyfit_pow(3.0f, 4), 81.0f, 1e-5f); +} + +TEST(PolyfitPow, NegativeExponent) { + EXPECT_NEAR(polyfit_pow(2.0f, -2), 0.25f, 1e-7f); +} + +TEST(PolyfitFabs, Positive) { EXPECT_FLOAT_EQ(polyfit_fabs(3.14f), 3.14f); } +TEST(PolyfitFabs, Negative) { EXPECT_FLOAT_EQ(polyfit_fabs(-3.14f), 3.14f); } +TEST(PolyfitFabs, Zero) { EXPECT_FLOAT_EQ(polyfit_fabs(0.0f), 0.0f); } +TEST(PolyfitFabs, NaN) { + float nan_val = 0.0f / 0.0f; + EXPECT_TRUE(std::isnan(polyfit_fabs(nan_val))); +} + +TEST(PolyfitIsNearlyZero, BelowThresholdIsTrue) { + EXPECT_TRUE(polyfit_is_nearly_zero(1e-8f, 1e-6f)); +} + +TEST(PolyfitIsNearlyZero, AboveThresholdIsFalse) { + EXPECT_FALSE(polyfit_is_nearly_zero(1e-5f, 1e-6f)); +} + +TEST(PolyfitIsNearlyZero, ExactlyAtThresholdIsFalse) { + // strictly less than threshold required + EXPECT_FALSE(polyfit_is_nearly_zero(1e-6f, 1e-6f)); +} diff --git a/tools/CI.jenkinsfile b/tools/CI.jenkinsfile deleted file mode 100644 index ec9819a..0000000 --- a/tools/CI.jenkinsfile +++ /dev/null @@ -1,427 +0,0 @@ -#!groovy -@Library('jenkins-pipeline-lib@pj/new-bs') _ - -pipeline -{ - agent any - stages - { - stage('Clean') - { - when - { - expression - { - /* - * If the previous build suceeeded (unstable means test failed but build passed) - * then we continue on in CI mode. If the previous build failed we want to - * start with a clean environment. This is done to reduce manual user interation. - */ - return !(didLastBuildSucceed()) - } - } - steps - { - echo('Previous build failed: Running a clean build.') - sh 'make distclean' - } - } - stage('Format') - { - steps - { - clangFormat() - } - } - stage('Build for Clang') - { - steps - { - sh 'make' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - clang(), - ] - ) - } - } - } - stage('Build for GCC-9') - { - steps - { - sh 'make NATIVE=gcc-9 BUILDRESULTS=buildresults/gcc-9' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/gcc-9', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - gcc(id:'gcc-9', name: 'gcc-9'), - ] - ) - } - } - } - stage('Build for GCC-8') - { - steps - { - sh 'make NATIVE=gcc-8 BUILDRESULTS=buildresults/gcc-8' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/gcc-8/', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - gcc(id: 'gcc-8', name: 'gcc-8'), - ] - ) - } - } - } - stage('Build for GCC-7') - { - steps - { - sh 'make NATIVE=gcc-7 BUILDRESULTS=buildresults/gcc-7' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/gcc-7', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - gcc(id: 'gcc-7', name: 'gcc-7'), - ] - ) - } - } - } - stage('Cross compile for ARM') - { - steps - { - sh 'make CROSS=cortex-m4_hardfloat BUILDRESULTS=buildresults/arm' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/arm', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - gcc(id: 'gcc-arm', name: 'gcc-arm'), - ] - ) - } - } - } - stage('Test') - { - steps - { - sh 'make test' - } - post - { - always - { - junit 'buildresults/test/*.xml' - } - } - } - stage('Complexity') - { - steps - { - sh 'make complexity' - } - } - stage('CppCheck') - { - steps - { - sh 'make cppcheck-xml' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - cppCheck( - pattern: 'buildresults/**/cppcheck.xml', - ), - ] - ) - } - } - } - stage('Clang Tidy') - { - steps - { - sh 'make tidy' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - clangTidy(), - ] - ) - } - } - } - stage('Clang Analyzer') - { - steps - { - sh 'make scan-build' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - clang(id: 'scan-build', name: 'scan-build'), - ] - ) - } - } - } - stage('sloccount') - { - steps - { - sh 'make sloccount-report-full' - } - post - { - success - { - sloccountPublish encoding: '', ignoreBuildFailure: true, pattern: 'buildresults/sloccount_detailed.sc' - } - } - } - stage('Coverage') - { - steps - { - sh 'make coverage' - } - post - { - success - { - cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'buildresults/coverage/coverage-xml.xml', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false - } - } - } - stage('Lint Documentation') - { - steps - { - sh 'make vale' - } - } - stage('Generate Documentation') - { - steps - { - sh 'make docs' - } - } - stage('Generate Release') - { - steps - { - sh 'make package' - } - } - } - post - { - always - { - // Scan for open tasks, warnings, issues, etc. - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - taskScanner( - excludePattern: 'buildresults/**, cmake/**', - includePattern: '**/*.c, **/*.cpp, **/*.h, **/*.hpp, **/*.sh, **/*.build', - normalTags: 'TODO, to do, WIP', - highTags: 'FIXME, FIX', - ignoreCase: true, - ), - ] - ) - } - } -} diff --git a/tools/Jenkinsfile b/tools/Jenkinsfile deleted file mode 100644 index ae29eed..0000000 --- a/tools/Jenkinsfile +++ /dev/null @@ -1,449 +0,0 @@ -#!groovy -@Library('jenkins-pipeline-lib') _ - -pipeline -{ - agent any - environment - { - GIT_CHANGE_LOG = gitChangeLog(currentBuild.changeSets) - } - parameters - { - string(defaultValue: '0', description: 'Major version number (x.0.0)', name: 'MAJOR_VERSION') - string(defaultValue: '1', description: 'Minor version number (0.x.0)', name: 'MINOR_VERSION') - } - triggers - { - //At 04:00 on every day-of-week from Monday through Friday. - pollSCM('H 4 * * 1-5') - } - stages - { - stage('Setup') - { - steps - { - gitTagPreBuild "${params.MAJOR_VERSION}.${params.MINOR_VERSION}.${BUILD_NUMBER}" - - echo 'Removing existing build results' - sh 'make distclean' - } - } - stage('Build for Clang') - { - steps - { - sh 'make' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - clang(), - ] - ) - } - } - } - stage('Build for GCC-9') - { - steps - { - sh 'make NATIVE=gcc-9 BUILDRESULTS=buildresults/gcc-9' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/gcc-9', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - gcc(id:'gcc-9', name: 'gcc-9'), - ] - ) - } - } - } - stage('Build for GCC-8') - { - steps - { - sh 'make NATIVE=gcc-8 BUILDRESULTS=buildresults/gcc-8' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/gcc-8/', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - gcc(id: 'gcc-8', name: 'gcc-8'), - ] - ) - } - } - } - stage('Build for GCC-7') - { - steps - { - sh 'make NATIVE=gcc-7 BUILDRESULTS=buildresults/gcc-7' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/gcc-7', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - gcc(id: 'gcc-7', name: 'gcc-7'), - ] - ) - } - } - } - stage('Cross compile for ARM') - { - steps - { - sh 'make CROSS=cortex-m4_hardfloat BUILDRESULTS=buildresults/arm' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - sourceDirectory: 'buildresults/arm', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - gcc(id: 'gcc-arm', name: 'gcc-arm'), - ] - ) - } - } - } - stage('Test') - { - steps - { - sh 'make test' - } - post - { - always - { - junit 'buildresults/test/*.xml' - } - } - } - stage('Complexity') - { - steps - { - sh 'make complexity' - } - } - stage('CppCheck') - { - steps - { - sh 'make cppcheck-xml' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - cppCheck( - pattern: 'buildresults/**/cppcheck.xml', - ), - ] - ) - } - } - } - stage('Clang Tidy') - { - steps - { - sh 'make tidy' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - clangTidy(), - ] - ) - } - } - } - stage('Clang Analyzer') - { - steps - { - sh 'make scan-build' - } - post - { - always - { - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/project-skeleton/master', - filters: [ - excludeFile('subprojects/*') - ], - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - clang(id: 'scan-build', name: 'scan-build'), - ] - ) - } - } - } - stage('sloccount') - { - steps - { - sh 'make sloccount-report-full' - } - post - { - success - { - sloccountPublish encoding: '', ignoreBuildFailure: true, pattern: 'buildresults/sloccount_detailed.sc' - } - } - } - stage('Coverage') - { - steps - { - sh 'make coverage' - } - post - { - success - { - cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'buildresults/coverage/coverage-xml.xml', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false - } - } - } - stage('Lint Documentation') - { - steps - { - sh 'make vale' - } - } - stage('Generate Documentation') - { - steps - { - sh 'make docs' - } - } - stage('Generate Release') - { - steps - { - sh 'make package' - } - } - stage('Archive') - { - steps - { - dir('buildresults/releases') - { - archiveArtifacts '*.tgz' - } - } - } - } - post - { - always - { - // Scan for open tasks, warnings, issues, etc. - recordIssues( - healthy: 5, - unhealthy: 10, - aggregatingResults: true, - referenceJobName: 'ea-nightly/cmake-project-skeleton/master', - qualityGates: [ - // 3 new issue: unstable - [threshold: 3, type: 'DELTA', unstable: true], - // 5 new issues: failed build - [threshold: 5, type: 'DELTA', unstable: false], - // 10 total issues: unstable - [threshold: 10, type: 'TOTAL', unstable: true], - // 20 total issues: fail - [threshold: 20, type: 'TOTAL', unstable: false] - ], - tools: [ - taskScanner( - excludePattern: 'buildresults/**, cmake/**', - includePattern: '**/*.c, **/*.cpp, **/*.h, **/*.hpp, **/*.sh, **/*.build', - normalTags: 'TODO, to do, WIP', - highTags: 'FIXME, FIX', - ignoreCase: true, - ), - ] - ) - - gitTagCleanup "${params.MAJOR_VERSION}.${params.MINOR_VERSION}.${BUILD_NUMBER}" - } - success - { - gitTagSuccess "${params.MAJOR_VERSION}.${params.MINOR_VERSION}.${BUILD_NUMBER}" - } - failure - { - /* - * This job does not have a GitHub configuration, - * so we need to create a dummy config - */ - githubSetConfig('69e4682e-2951-492f-b828-da06364c322d') - githubFileIssue() - emailNotify(currentBuild.currentResult) - } - } -} diff --git a/tools/deploy_skeleton.sh b/tools/deploy_skeleton.sh deleted file mode 100755 index 74258eb..0000000 --- a/tools/deploy_skeleton.sh +++ /dev/null @@ -1,170 +0,0 @@ -#!/bin/bash - -USE_GIT=1 -USE_SUBMODULES=1 -USE_ADR=0 -USE_POTTERY=0 -COPY_LICENSE=0 -REPLACE_NAME= -CORE_FILES="docs src test tools .clang-format .clang-tidy BuildOptions.cmake CMakeLists.txt Makefile Packaging.cmake README.md" -GIT_FILES=".gitattributes .github .gitignore" -SUBMODULE_DIRS=("cmake") -SUBMODULE_URLS=("https://github.com/embeddedartistry/cmake-buildsystem.git") - -# Detect sed -i command b/c OS X uses BSD sed -if [ "$(uname)" == "Darwin" ]; then - SED="sed -i ''" -else - SED="sed -i" -fi - -# Parse optional arguments -while getopts aplghsr: opt; do - case $opt in - a) USE_ADR=1 - ;; - p) USE_POTTERY=1 - ;; - l) COPY_LICENSE=1 - ;; - g) USE_GIT=0 - USE_SUBMODULES=0 - ;; - s) USE_SUBMODULES=0 - ;; - r) REPLACE_NAME="$OPTARG" - ;; - h) # Help - echo "Usage: deploy_skeleton.sh [optional ags] dest_dir" - echo "Optional args:" - echo " -a: initialize destination to use adr-tools" - echo " -p: initialize destination to use pottery" - echo " -l: copy the license file" - echo " -g: Assume non-git environment. Installs submodule files directly." - echo " -s: Don't use submodules, and copy files directly" - echo " -r : Replace template project/app name values with specified name" - exit 0 - ;; - \?) echo "Invalid option -$OPTARG" >&2 - ;; - esac -done - -# Shift off the getopts args, leaving us with positional args -shift $((OPTIND -1)) - -# First positional argument is the destination folder that skeleton files will be installed to -DEST_DIR=$1 -STARTING_DIR=$PWD - -# Check to see if we're in tools/ or the project-skeleton root -CHECK_DIR=cmake -if [ ! -d "$CHECK_DIR" ]; then - cd .. - if [ ! -d "$CHECK_DIR" ]; then - echo "This script must be run from the project skeleton root or the tools/ directory." - exit 1 - fi -fi - -# Adjust the destination directory for relative paths in case we changed directories -# This method still supports absolute directory paths for the destination -if [ ! -d "$DEST_DIR" ]; then - if [ -d "$STARTING_DIR/$DEST_DIR" ]; then - DEST_DIR=$STARTING_DIR/$DEST_DIR - else - echo "Destination directory cannot be found. Does it exist?" - exit 1 - fi -fi - -# Copy core skeleton files to the destination -cp -r $CORE_FILES $DEST_DIR - -# Delete the deploy skeleton script from the destination -rm $DEST_DIR/tools/deploy_skeleton.sh $DEST_DIR/tools/download_and_deploy.sh - -# Copy git files to the destination -if [ $USE_GIT == 1 ]; then - cp -r $GIT_FILES $DEST_DIR -fi - -# Manually copy submodule files -if [ $USE_SUBMODULES == 0 ]; then - git submodule update --init --recursive - cp -r ${SUBMODULE_DIRS[@]} $DEST_DIR -fi - -if [ $COPY_LICENSE == 1 ]; then - cp LICENSE $DEST_DIR -fi - -## The following operations all take place in the destination directory -cd $DEST_DIR - -# Initialize Submodules -if [ $USE_SUBMODULES == 1 ]; then - cd $DEST_DIR - for index in ${!SUBMODULE_URLS[@]}; do - git submodule add ${SUBMODULE_URLS[$index]} ${SUBMODULE_DIRS[$index]} - done - git commit -m "Add submodules from project skeleton." -else - find ${SUBMODULE_DIRS[@]} -name ".git*" -exec rm -rf {} \; -fi - -# Commit Files -if [ $USE_GIT == 1 ]; then - git add --all - git commit -m "Initial commit of project skeleton files." -fi - -# Replace placeholder names -if [[ ! -z $REPLACE_NAME ]]; then - # Convert spaces to underscores before replacing names - REPLACE_NAME=${REPLACE_NAME// /_} - eval $SED "s/MYPROJECT/$REPLACE_NAME/g" "CMakeLists.txt" - eval $SED "s/MYPROJECT/$REPLACE_NAME/g" "test/CMakeLists.txt" - # Convert to all upper case for variable name - # We use awk beacuse it properly handles UTF-8/multibyte input - REPLACE_NAME=$(echo "$REPLACE_NAME" | awk '{print toupper($0)}') - eval $SED "s/PROJECTVARNAME/$REPLACE_NAME/g" "CMakeLists.txt" - eval $SED "s/PROJECTVARNAME/$REPLACE_NAME/g" "test/CMakeLists.txt" - eval $SED "s/PROJECTVARNAME/$REPLACE_NAME/g" "BuildOptions.cmake" - if [ $USE_GIT == 1 ]; then - git commit -am "Replace placeholder values in build files with $REPLACE_NAME." - fi -fi - -# Initialize adr-tools -if [ $USE_ADR == 1 ]; then - adr init docs/ - if [ $USE_GIT == 1 ]; then - git add --all - git commit -m "Initialize adr-tools." - fi -fi - -# Initialize pottery -if [ $USE_POTTERY == 1 ]; then - pottery init - pottery note "Initial creation of project repository" - if [ $USE_GIT == 1 ]; then - git add --all - git commit -m "Initialize pottery and document repository creation." - fi -fi - -# Push all changes to the server -if [ $USE_GIT == 1 ]; then - git push || echo "WARNING: git push failed: check repository." -fi - -if [[ $COPY_LICENSE == 0 && ! -f "LICENSE" || ! -f "LICENSE.md" ]]; then - echo "NOTE: Your project does not have a LICENSE or LICENSE.md file in the project root." -fi - -if [[ -z $REPLACE_NAME ]]; then - echo "NOTE: Replace the placeholder project name values in CMakeLists.txt and test/CMakeLists.txt (MYPROJECT)" - echo "NOTE: Replace the placeholder project variable values in CMakeLists.txt, test/CMakeLists.txt, and BuildOptions.cmake (PROJECTVARNAME)" -fi diff --git a/tools/download_and_deploy.sh b/tools/download_and_deploy.sh deleted file mode 100755 index 8b1d9d1..0000000 --- a/tools/download_and_deploy.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# This script forwards all arguments to the deploy_skeleton.sh script -# The directory supplied to the script *must* be an absolute path! - -cd /tmp -git clone git@github.com:embeddedartistry/cmake-project-skeleton.git --recursive --depth 1 -cd project-skeleton -bash tools/deploy_skeleton.sh $@ -cd ../ -rm -rf project-skeleton diff --git a/tools/install_arm_gcc.sh b/tools/install_arm_gcc.sh deleted file mode 100755 index 4b628d7..0000000 --- a/tools/install_arm_gcc.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# -# You can override the installation path for toolchains by defining TOOLCHAIN_INSTALL_DIR -# If the toolchain directory do not require sudo permissions, disable the use -# of sudo by defining TOOLCHAIN_DISABLE_SUDO=1 - -TOOLCHAIN_INSTALL_DIR=${TOOLCHAIN_INSTALL_DIR:-/usr/local/toolchains} -TOOLCHAIN_DISABLE_SUDO=${TOOLCHAIN_DISABLE_SUDO:-0} - -TOOLCHAIN_SUDO=sudo -if [ $TOOLCHAIN_DISABLE_SUDO == 1 ]; then - - TOOLCHAIN_SUDO= -fi - -OSX_ARM_URL="https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-mac.tar.bz2" -LINUX_ARM_URL="https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major-aarch64-linux.tar.bz2" - -if [ "$(uname)" == "Darwin" ]; then - ARM_URL=$OSX_ARM_URL - ARM_DIR=$(basename "$ARM_URL" -mac.tar.bz2) -else - ARM_URL=$LINUX_ARM_URL - ARM_DIR=$(basename "$ARM_URL" -aarch64-linux.tar.bz2) -fi - -ARM_ARCHIVE=$(basename "$ARM_URL") - -################################### -# Download and install dependency # -################################### - -cd /tmp -wget $ARM_URL -${TOOLCHAIN_SUDO} mkdir -p ${TOOLCHAIN_INSTALL_DIR} -# Move current toolchain if it exists -if [ -d "${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi" ]; then - ${TOOLCHAIN_SUDO} rm -rf ${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi-bak - ${TOOLCHAIN_SUDO} mv ${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi ${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi-bak -fi -${TOOLCHAIN_SUDO} tar xf ${ARM_ARCHIVE} --directory ${TOOLCHAIN_INSTALL_DIR} -${TOOLCHAIN_SUDO} mv ${TOOLCHAIN_INSTALL_DIR}/${ARM_DIR} ${TOOLCHAIN_INSTALL_DIR}/gcc-arm-none-eabi -rm ${ARM_ARCHIVE} diff --git a/tools/install_deps.sh b/tools/install_deps.sh deleted file mode 100755 index 30933da..0000000 --- a/tools/install_deps.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/bin/bash - -STARTING_DIR=$PWD -UPDATE=0 -PIP_UPDATE= -BREW_COMMAND="install" -APT_COMMAND="install" -UPDATE_ENV=0 -TOOLCHAIN_INSTALL_DIR=${TOOLCHAIN_INSTALL_DIR:-/usr/local/toolchains} -TOOL_INSTALL_DIR=${TOOL_INSTALL_DIR:-/usr/local/tools} -TOOLCHAIN_DISABLE_SUDO=${TOOLCHAIN_DISABLE_SUDO:-0} -TOOL_DISABLE_SUDO=${TOOL_DISABLE_SUDO:-0} -TOOLS_SUDO=sudo - -if [ $TOOL_DISABLE_SUDO == 1 ]; then - TOOLS_SUDO= -fi - -# Packages to Install -BREW_PACKAGES=("python3" "ninja" "wget" "gcc@7" "gcc@8" "gcc@9" "llvm" "adr-tools" "cmocka" "pkg-config") -BREW_PACKAGES+=("vale" "doxygen" "cppcheck" "clang-format" "gcovr" "lcov" "sloccount" "cmake") -APT_PACKAGES=("python3" "python3-pip" "ninja-build" "wget" "build-essential" "clang" "lld" "llvm") -APT_PACKAGES+=("clang-tools" "libcmocka0" "libcmocka-dev" "pkg-config" "sloccount" "curl") -APT_PACKAGES+=("doxygen" "cppcheck" "gcovr" "lcov" "clang-format" "clang-tidy" "clang-tools") -APT_PACKAGES+=("gcc-7" "g++-7" "gcc-8" "g++-8" "gcc-9" "g++-9") -PIP3_PACKAGES=("lizard") - -while getopts "euh" opt; do - case $opt in - e) UPDATE_ENV=1 - ;; - u) UPDATE=1 - PIP_UPDATE="--upgrade" - BREW_COMMAND="upgrade" - APT_COMMAND="upgrade" - ;; - h) # Help - echo "Usage: install_deps.sh [optional ags]" - echo "Optional args:" - echo " -u: Run an update instead of install" - echo " -e: Include environment setup during install process (.bashrc + .bash_profile)" - exit 0 - ;; - \?) echo "Invalid option -$OPTARG" >&2 - ;; - esac -done - -if [ "$(uname)" == "Darwin" ]; then - # OS X case - ARM_URL=$OSX_ARM_URL - ARM_DIR=$(basename "$ARM_URL" -mac.tar.bz2) - - if [ $UPDATE == 1 ]; then - # update homebrew - brew update - else - #install brew if unavailable - if [ -z "$(command -v brew)" ]; then - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" - fi - - brew tap homebrew/cask-versions - fi - - brew ${BREW_COMMAND} ${BREW_PACKAGES[@]} - pip3 install ${PIP3_PACKAGES[@]} ${PIP_UPDATE} -else - # WSL/Linux Case - ARM_URL=$LINUX_ARM_URL - ARM_DIR=$(basename "$ARM_URL" -aarch64-linux.tar.bz2) - - sudo apt-get update - sudo apt ${APT_COMMAND} -y ${APT_PACKAGES[@]} - sudo -H pip3 install ${PIP3_PACKAGES[@]} ${PIP_UPDATE} - - cd /tmp - wget https://install.goreleaser.com/github.com/ValeLint/vale.sh - sudo sh vale.sh -b /usr/local/bin - rm vale.sh - - # Install adr-tools - if [ $UPDATE == 1 ]; then - cd /usr/local/tools/adr-tools - ${TOOLS_SUDO} git pull - else - ${TOOLS_SUDO} mkdir -p /usr/local/tools - cd /usr/local/tools - ${TOOLS_SUDO} git clone https://github.com/npryce/adr-tools.git --recursive - fi -fi - -########################### -# Common Dependency Steps # -########################### - -# Install gcc-arm-none-eabi -if [ $UPDATE == 0 ]; then - # Assume that the two scripts are contained in the same directory - cd $STARTING_DIR - source $(dirname $0)/install_arm_gcc.sh -fi - -if [ $UPDATE == 1 ]; then - # Update Pottery - cd ${TOOL_INSTALL_DIR}/pottery - ${TOOLS_SUDO} git pull -else - ${TOOLS_SUDO} mkdir -p ${TOOL_INSTALL_DIR}/tools - cd /usr/local/tools - ${TOOLS_SUDO} git clone https://github.com/npryce/pottery.git --recursive -fi - -############################# -# Configure the Environment # -############################# - -if [ $UPDATE == 0 ]; then - if [ $UPDATE_ENV == 1 ]; then - # Assume that the two scripts are contained in the same directory - cd $STARTING_DIR - source $(dirname $0)/setup_env.sh - else - echo "You may need to manually modify your PATH to reference the programs in $TOOLCHAIN_INSTALL_DIR and $TOOL_INSTALL_DIR" - fi -fi diff --git a/tools/setup_env.sh b/tools/setup_env.sh deleted file mode 100755 index bf9862a..0000000 --- a/tools/setup_env.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -TOOLCHAIN_INSTALL_DIR=${TOOLCHAIN_INSTALL_DIR:-/usr/local/toolchains} -TOOL_INSTALL_DIR=${TOOL_INSTALL_DIR:-/usr/local/tools} - -# For OS X, we need .bash_profile to invoke `.bashrc`. -# Append to file in case it already exists -if [ "$(uname)" == "Darwin" ]; then -cat << ENDOFBLOCK >> $HOME/.bash_profile -if [ -f \$HOME/.bashrc ]; then - source \$HOME/.bashrc -fi -ENDOFBLOCK -fi - -PATHMOD="$TOOLCHAIN_INSTALL_DIR/gcc-arm-none-eabi/bin:$TOOL_INSTALL_DIR/pottery/src" -if [ "$(uname)" == "Darwin" ]; then - PATHMOD="$PATHMOD:/usr/local/opt/llvm/bin" -else - PATHMOD="$PATHMOD:$TOOL_INSTALL_DIR:adr-tools/src" -fi - - -cat << ENDOFBLOCK >> $HOME/.bashrc -################ -# Path Updates # -################ - -export PATH="$PATHMOD:\$PATH" -# set PATH so it includes user's private bin if it exists -if [ -d "\$HOME/bin" ] ; then - PATH="\$HOME/bin:\$PATH" -fi -ENDOFBLOCK - -cat << ENDOFBLOCK >> $HOME/.bashrc -######################### -# Aliases and Functions # -######################### -function deploy_skeleton() -{ - INITIAL_DIR=\$(pwd) - cd /tmp - wget https://gist.githubusercontent.com/phillipjohnston/bb95f19d156007f99be4c10c1efdf694/raw/f2f141e31fca0a12eb391e8251efe2ce1f9e68bd/download_and_deploy.sh - bash download_and_deploy.sh \$@ - rm download_and_deploy.sh - cd \$INITIAL_DIR -} -alias init_skeleton='deploy_skeleton -a -p `pwd`' -function init_repo() -{ - URL=\$1 - shift - git clone \$URL - cd \$(basename "\$URL" .git) - deploy_skeleton -a -p \${@} `pwd` -} - -# Skeleton Update Aliases -alias sm_update_build="cd build; git checkout master; git pull; cd ../" -alias sm_update_commit_build="cd build; git checkout master; git pull; cd ../; git add build; git commit -m 'Update build submodule to master'" -ENDOFBLOCK