Initial commit
- Update various docs. - Setup Azure Pipelines. - Moved source files from nanoframework/nf-tools. Signed-off-by: José Simões <jose.simoes@eclo.solutions>
This commit is contained in:
Родитель
f2274130d9
Коммит
6d51981b4a
|
@ -0,0 +1,63 @@
|
|||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
|
@ -1,330 +1,17 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
# Visual Studio
|
||||
.vs/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
packages/
|
||||
*.suo
|
||||
*.user
|
||||
NanoFramework-GitHubBot - Web Deploy.pubxml
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
# AzureDevOps tasks
|
||||
ps_modules
|
||||
7zip
|
||||
*.vsix
|
||||
*.zip
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
#SoundCloud
|
||||
*.sonarqube/
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Contributor Code of Conduct
|
||||
|
||||
Please refer to the contributor Code of Conduct at the Home repository [here](https://github.com/nanoframework/Home/blob/master/CODE_OF_CONDUCT.md).
|
|
@ -0,0 +1,3 @@
|
|||
# Contributing to **nanoFramework**
|
||||
|
||||
Please refer to the contribution guidelines at the Home repository [here](https://github.com/nanoframework/Home/blob/master/CONTRIBUTING.md).
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 nanoFramework
|
||||
Copyright (c) 2019 nanoFramework contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/master/CONTRIBUTING.md) [![Build Status](https://dev.azure.com/nanoframework/tools/_apis/build/status/nanoframework.nf-tool-hex2dfu)](https://dev.azure.com/nanoframework/tools/_build/latest?definitionId=) [![Discord](https://img.shields.io/discord/478725473862549535.svg)](https://discord.gg/gCyBu8T)
|
||||
|
||||
![nanoFramework logo](https://github.com/nanoframework/Home/blob/master/resources/logo/nanoFramework-repo-logo.png)
|
||||
|
||||
-----
|
||||
|
||||
### Welcome to the **nanoFramework** HEX2DFU tool repository!
|
||||
|
||||
This repo contains the Hex2Dfu tool.
|
||||
It's a console app to convert and/or pack HEX or BIN files in DFU packages (required to update some target boards).
|
||||
Is part of **nanoFramework** toolbox, along with other various tools that are required in **nanoFramework** development, usage or repository management.
|
||||
|
||||
## Feedback and documentation
|
||||
|
||||
For documentation, providing feedback, issues and finding out how to contribute please refer to the [Home repo](https://github.com/nanoframework/Home).
|
||||
|
||||
Join our Discord community [here](https://discord.gg/gCyBu8T).
|
||||
|
||||
## Credits
|
||||
|
||||
The list of contributors to this project can be found at [CONTRIBUTORS](https://github.com/nanoframework/Home/blob/master/CONTRIBUTORS.md).
|
||||
|
||||
## License
|
||||
|
||||
The **nanoFramework** HEX2DFU tool is licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||
|
||||
## Code of Conduct
|
||||
This project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/)
|
||||
to clarify expected behavior in our community.
|
|
@ -0,0 +1,132 @@
|
|||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- develop
|
||||
- release/*
|
||||
paths:
|
||||
exclude:
|
||||
- /*.md
|
||||
- .gitignore
|
||||
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- develop
|
||||
- release/*
|
||||
autoCancel: true
|
||||
|
||||
# add nf-tools repo to resources (for Azure Pipelines templates)
|
||||
resources:
|
||||
repositories:
|
||||
- repository: templates
|
||||
type: github
|
||||
name: nanoframework/nf-tools
|
||||
endpoint: nanoframework
|
||||
|
||||
jobs:
|
||||
|
||||
##############################
|
||||
- job: Get_Build_Options
|
||||
pool:
|
||||
vmImage: 'VS2017-Win2016'
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
|
||||
# build tools
|
||||
- job: Build_tools
|
||||
|
||||
pool:
|
||||
vmImage: 'VS2017-Win2016'
|
||||
|
||||
variables:
|
||||
buildPlatform: 'Any CPU'
|
||||
buildConfiguration: 'Release'
|
||||
solution: 'source\nanoFramework.Tools.Hex2Dfu.sln'
|
||||
toolName: 'HEX2DFU utility'
|
||||
|
||||
steps:
|
||||
|
||||
# need this here in order to persist GitHub credentials
|
||||
- checkout: self
|
||||
persistCredentials: true
|
||||
|
||||
- script: |
|
||||
git config --global user.email "nanoframework@outlook.com"
|
||||
git config --global user.name "nfbot"
|
||||
displayName: Setup git identity
|
||||
|
||||
- task: NuGetToolInstaller@0
|
||||
|
||||
- task: NuGetCommand@2
|
||||
inputs:
|
||||
restoreSolution: '$(solution)'
|
||||
verbosityRestore: quiet
|
||||
|
||||
- task: VSBuild@1
|
||||
inputs:
|
||||
solution: '$(solution)'
|
||||
platform: '$(buildPlatform)'
|
||||
configuration: '$(buildConfiguration)'
|
||||
|
||||
- task: CopyFiles@1
|
||||
inputs:
|
||||
sourceFolder: $(Build.SourcesDirectory)
|
||||
Contents: |
|
||||
**\bin\Release\*.exe
|
||||
TargetFolder: '$(Build.ArtifactStagingDirectory)'
|
||||
flattenFolders: true
|
||||
condition: succeeded()
|
||||
displayName: Collecting deployable artifacts
|
||||
|
||||
# publish artifacts (only possible if this is not a PR originated on a fork)
|
||||
- task: PublishBuildArtifacts@1
|
||||
inputs:
|
||||
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
|
||||
ArtifactName: deployables
|
||||
ArtifactType: Container
|
||||
condition: and( succeeded(), ne(variables['system.pullrequest.isfork'], true) )
|
||||
displayName: Publish deployables artifacts
|
||||
|
||||
# create or update GitHub release
|
||||
- task: GitHubReleasePublish@1
|
||||
inputs:
|
||||
githubEndpoint: 'nanoFramework'
|
||||
githubOwner: 'nanoframework'
|
||||
githubRepositoryName: 'nf-tool-hex2dfu'
|
||||
githubTag: v$(NBGV_Version)
|
||||
githubReleaseTitle: 'nanoFramework hex2dfu v$(NBGV_Version)'
|
||||
githubReleaseNotes: 'add description here'
|
||||
githubTargetCommitsh: $(Build.SourceVersion)
|
||||
githubReleaseDraft: true
|
||||
githubReleasePrerelease: false
|
||||
githubReuseDraftOnly: true
|
||||
githubReuseRelease: true
|
||||
githubEditRelease: true
|
||||
githubReleaseAsset: '$(Build.ArtifactStagingDirectory)/*.exe'
|
||||
condition: and( succeeded(), not( startsWith(variables['Build.SourceBranch'], 'refs/pull') ) )
|
||||
displayName: Create/Update GitHub release
|
||||
|
||||
##################################
|
||||
# report build failure to Discord
|
||||
- job: Report_Build_Failure
|
||||
dependsOn:
|
||||
- Build_tools
|
||||
condition: failed('Build_tools')
|
||||
|
||||
pool:
|
||||
vmImage: 'VS2017-Win2016'
|
||||
|
||||
steps:
|
||||
|
||||
- checkout: self
|
||||
fetchDepth: 1
|
||||
|
||||
# step from template @ nf-tools repo
|
||||
- template: azure-pipelines-templates/discord-webhook.yml@templates
|
||||
parameters:
|
||||
status: 'failure'
|
||||
webhookUrl: '$(DiscordWebhook)'
|
||||
message: ''
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
|
||||
</startup>
|
||||
</configuration>
|
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀ ▀ ▀ ▀▀
|
||||
█
|
||||
█ ▄████████
|
||||
█ ███ ███
|
||||
█ ███ ███ █████ ▄████▄ ██ █ ▄▄██▄▄▄ ▄█████ ██▄▄▄▄ ██ ▄█████
|
||||
█ ███ ███ ██ ██ ██ ▀ ██ ██ ▄█▀▀██▀▀█▄ ██ █ ██▀▀▀█▄ ▀███████▄ ██ ▀
|
||||
█ ▀███████████ ▄██▄▄█▀ ▄██ ██ ██ ██ ██ ██ ▄██▄▄ ██ ██ ██ ▀ ██
|
||||
█ ███ ███ ▀███████ ▀▀██ ███▄ ██ ██ ██ ██ ██ ▀▀██▀▀ ██ ██ ██ ▀███████
|
||||
█ ███ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ █ ██ ██ ██ ▄ ██
|
||||
█ ███ █▀ ██ ██ ██████▀ ██████ █ ██ █ ███████ █ █ ▄██▀ ▄████▀
|
||||
█
|
||||
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄▄ ▄▄ ▄▄▄▄ ▄▄ ▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄
|
||||
█████████████████████████████████████████████████████████████ ███████████████ ██ ██ ██ ████ ██ ██ ████████████████ █ █
|
||||
▄
|
||||
█ Provides static methods used to retrieve the command line arguments and operands with which the application was started,
|
||||
█ as well as a Type to contain them.
|
||||
█
|
||||
█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀▀ ▀▀ ▀
|
||||
█ The MIT License (MIT)
|
||||
█
|
||||
█ Copyright (c) 2017 JP Dillingham (jp@dillingham.ws)
|
||||
█
|
||||
█ 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.
|
||||
█
|
||||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀██
|
||||
██
|
||||
▀█▄ ██ ▄█▀
|
||||
▀████▀
|
||||
▀▀ */
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "Reviewed.")]
|
||||
|
||||
namespace Utility.CommandLine
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension method(s) for the Argument namespace.
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
#region Internal Methods
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified key to the specified dictionary with the specified value, but only if the specified key is not
|
||||
/// already present in the dictionary. If it is present, a list is created and the new value is added to the list,
|
||||
/// along with all subsequent values.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">The dictionary to which they specified key and value are to be added.</param>
|
||||
/// <param name="key">The key to add to the dictionary.</param>
|
||||
/// <param name="value">The value corresponding to the specified key.</param>
|
||||
internal static void ExclusiveAdd(this Dictionary<string, object> dictionary, string key, object value)
|
||||
{
|
||||
if (!dictionary.ContainsKey(key))
|
||||
{
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = dictionary[key].GetType();
|
||||
|
||||
if (dictionary[key].GetType() == typeof(List<object>))
|
||||
{
|
||||
((List<object>)dictionary[key]).Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
object existingValue = dictionary[key];
|
||||
|
||||
dictionary[key] = new List<object>(new object[] { existingValue, value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Internal Methods
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the property is to be used as a target for automatic population of values from command line arguments
|
||||
/// when invoking the <see cref="Arguments.Populate(string)"/> method.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public class ArgumentAttribute : Attribute
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArgumentAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="shortName">The short name of the argument, represented as a single character.</param>
|
||||
/// <param name="longName">The long name of the argument.</param>
|
||||
public ArgumentAttribute(char shortName, string longName)
|
||||
{
|
||||
ShortName = shortName;
|
||||
LongName = longName;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the long name of the argument.
|
||||
/// </summary>
|
||||
public string LongName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the short name of the argument.
|
||||
/// </summary>
|
||||
public char ShortName { get; set; }
|
||||
|
||||
#endregion Public Properties
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides static methods used to retrieve the command line arguments and operands with which the application was
|
||||
/// started, as well as a Type to contain them.
|
||||
/// </summary>
|
||||
public class Arguments
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// The regular expression with which to parse the command line string.
|
||||
/// </summary>
|
||||
private const string ArgumentRegEx = "(?:[-]{1,2}|\\/)([^=: ]+)[=: ]?(\\w\\S*|\\\"[^\"]*\\\"|\\\'[^']*\\\')?|([^ ([^'\\\"]+|\"[^\\\"]+\"|\\\'[^']+\\\')";
|
||||
|
||||
/// <summary>
|
||||
/// The regular expression with which to parse argument-value groups.
|
||||
/// </summary>
|
||||
private const string GroupRegEx = "^-[^-]+";
|
||||
|
||||
/// <summary>
|
||||
/// The regular expression with which to parse strings strictly containing operands.
|
||||
/// </summary>
|
||||
private const string OperandRegEx = "([^ ([^'\\\"]+|\\\"[^\\\"]+\\\"|\\\'[^']+\\\')";
|
||||
|
||||
/// <summary>
|
||||
/// The regular expression with which to split the command line string explicitly among argument/value pairs and
|
||||
/// operands, and strictly operands.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This regular expression effectively splits a string into two parts; the part before the first "--", and the part
|
||||
/// after. Instances of "--" not surrounded by a word boundary and those enclosed in quotes are ignored.
|
||||
/// </remarks>
|
||||
private const string StrictOperandSplitRegEx = "(.*?[^\\\"\\\'])?(\\B-{2}\\B)[^\\\"\\\']?(.*)";
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Arguments"/> class with the specified argument dictionary and operand list.
|
||||
/// </summary>
|
||||
/// <param name="argumentDictionary">
|
||||
/// The dictionary containing the arguments and values specified in the command line arguments with which the
|
||||
/// application was started.
|
||||
/// </param>
|
||||
/// <param name="operandList">
|
||||
/// The list containing the operands specified in the command line arguments with which the application was started.
|
||||
/// </param>
|
||||
private Arguments(Dictionary<string, object> argumentDictionary, List<string> operandList)
|
||||
{
|
||||
ArgumentDictionary = argumentDictionary;
|
||||
OperandList = operandList;
|
||||
}
|
||||
|
||||
#endregion Private Constructors
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary containing the arguments and values specified in the command line arguments with which the
|
||||
/// application was started.
|
||||
/// </summary>
|
||||
public Dictionary<string, object> ArgumentDictionary { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list containing the operands specified in the command line arguments with which the application was started.
|
||||
/// </summary>
|
||||
public List<string> OperandList { get; private set; }
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Indexers
|
||||
|
||||
/// <summary>
|
||||
/// Gets the argument value corresponding to the specified key from the <see cref="ArgumentDictionary"/> property.
|
||||
/// </summary>
|
||||
/// <param name="index">The key for which the value is to be retrieved.</param>
|
||||
/// <returns>The argument value corresponding to the specified key.</returns>
|
||||
public object this[string index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return ArgumentDictionary[index];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Indexers
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary containing the values specified in the command line arguments with which the application was
|
||||
/// started, keyed by argument name.
|
||||
/// </summary>
|
||||
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
|
||||
/// <returns>
|
||||
/// The dictionary containing the arguments and values specified in the command line arguments with which the
|
||||
/// application was started.
|
||||
/// </returns>
|
||||
public static Arguments Parse(string commandLineString = default(string))
|
||||
{
|
||||
commandLineString = commandLineString == default(string) || commandLineString == string.Empty ? Environment.CommandLine : commandLineString;
|
||||
|
||||
Dictionary<string, object> argumentDictionary;
|
||||
List<string> operandList;
|
||||
|
||||
// use the strict operand regular expression to test for/extract the two halves of the string, if the operator is used.
|
||||
MatchCollection matches = Regex.Matches(commandLineString, StrictOperandSplitRegEx);
|
||||
|
||||
// if there is a match, the string contains the strict operand delimiter. parse the first and second matches accordingly.
|
||||
if (matches.Count > 0)
|
||||
{
|
||||
// the first group of the first match will contain everything in the string prior to the strict operand delimiter,
|
||||
// so extract the argument key/value pairs and list of operands from that string.
|
||||
argumentDictionary = GetArgumentDictionary(matches[0].Groups[1].Value);
|
||||
operandList = GetOperandList(matches[0].Groups[1].Value);
|
||||
|
||||
// the first group of the second match will contain everything in the string after the strict operand delimiter, so
|
||||
// extract the operands from that string using the strict method.
|
||||
if (matches[0].Groups[3].Value != string.Empty)
|
||||
{
|
||||
List<string> operandListStrict = GetOperandListStrict(matches[0].Groups[3].Value);
|
||||
|
||||
// join the operand lists.
|
||||
operandList.AddRange(operandListStrict);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
argumentDictionary = GetArgumentDictionary(commandLineString);
|
||||
operandList = GetOperandList(commandLineString);
|
||||
}
|
||||
|
||||
return new Arguments(argumentDictionary, operandList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the properties in the invoking class marked with the
|
||||
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> with the values specified in the list of command line
|
||||
/// arguments, if present.
|
||||
/// </summary>
|
||||
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
|
||||
public static void Populate(string commandLineString = default(string))
|
||||
{
|
||||
Populate(new StackFrame(1).GetMethod().DeclaringType, Parse(commandLineString));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the properties in the specified Type marked with the
|
||||
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> with the values specified in the list of command line
|
||||
/// arguments, if present.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// The Type for which the static properties matching the list of command line arguments are to be populated.
|
||||
/// </param>
|
||||
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
|
||||
public static void Populate(Type type, string commandLineString = default(string))
|
||||
{
|
||||
Populate(type, Parse(commandLineString));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the properties in the invoking class marked with the
|
||||
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> with the values specified in the specified argument
|
||||
/// dictionary, if present.
|
||||
/// </summary>
|
||||
/// <param name="argumentDictionary">
|
||||
/// The dictionary containing the argument-value pairs with which the destination properties should be populated
|
||||
/// </param>
|
||||
public static void Populate(Dictionary<string, object> argumentDictionary)
|
||||
{
|
||||
Populate(new StackFrame(1).GetMethod().DeclaringType, new Arguments(argumentDictionary, new List<string>()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the properties in the specified Type marked with the
|
||||
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> with the values specified in the specified argument
|
||||
/// dictionary, if present. All property values are set to null at the start of the routine.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// The Type for which the static properties matching the list of command line arguments are to be populated.
|
||||
/// </param>
|
||||
/// <param name="arguments">
|
||||
/// The Arguments object containing the dictionary containing the argument-value pairs with which the destination
|
||||
/// properties should be populated and the list of operands.
|
||||
/// </param>
|
||||
public static void Populate(Type type, Arguments arguments)
|
||||
{
|
||||
// fetch any properties in the specified type marked with the ArgumentAttribute attribute and clear them
|
||||
Dictionary<string, PropertyInfo> properties = GetArgumentProperties(type);
|
||||
|
||||
ClearProperties(properties);
|
||||
|
||||
foreach (string propertyName in properties.Keys)
|
||||
{
|
||||
// if the argument dictionary contains a matching argument
|
||||
if (arguments.ArgumentDictionary.ContainsKey(propertyName))
|
||||
{
|
||||
// retrieve the property and type
|
||||
PropertyInfo property = properties[propertyName];
|
||||
Type propertyType = property.PropertyType;
|
||||
|
||||
// retrieve the value from the argument dictionary
|
||||
object value = arguments.ArgumentDictionary[propertyName];
|
||||
|
||||
bool valueIsList = value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(List<>);
|
||||
|
||||
object convertedValue;
|
||||
|
||||
// if the type of the property is bool and the argument value is empty set the property value to true,
|
||||
// indicating the argument is present
|
||||
if (propertyType == typeof(bool) && value.ToString() == string.Empty)
|
||||
{
|
||||
convertedValue = true;
|
||||
}
|
||||
else if (propertyType.IsArray || (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>)))
|
||||
{
|
||||
// if the property is an array or list, convert the value to an array or list of the matching type. start
|
||||
// by converting atomic values to a list containing a single value, just to simplify processing.
|
||||
if (valueIsList)
|
||||
{
|
||||
convertedValue = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
convertedValue = new List<object>(new object[] { value });
|
||||
}
|
||||
|
||||
// next, create a list with the same type as the target property
|
||||
Type valueType;
|
||||
|
||||
if (propertyType.IsArray)
|
||||
{
|
||||
valueType = propertyType.GetElementType();
|
||||
}
|
||||
else
|
||||
{
|
||||
valueType = propertyType.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
// create a list to store converted values
|
||||
Type valueListType = typeof(List<>).MakeGenericType(valueType);
|
||||
var valueList = (IList)Activator.CreateInstance(valueListType);
|
||||
|
||||
// populate the list
|
||||
foreach (object v in (List<object>)convertedValue)
|
||||
{
|
||||
valueList.Add(ChangeType(v, propertyName, valueType));
|
||||
}
|
||||
|
||||
// if the target property is an array, create one and populate it from the list this is surprisingly
|
||||
// difficult here because we created the source list with the Activator and ToArray() won't work easily.
|
||||
if (propertyType.IsArray)
|
||||
{
|
||||
var valueArray = Array.CreateInstance(propertyType.GetElementType(), valueList.Count);
|
||||
|
||||
for (int i = 0; i < valueArray.Length; i++)
|
||||
{
|
||||
valueArray.SetValue(valueList[i], i);
|
||||
}
|
||||
|
||||
convertedValue = valueArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
convertedValue = valueList;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the target property Type is an atomic (non-array or list) Type, convert the value and populate it,
|
||||
// but not if the value is an array or list.
|
||||
if (valueIsList)
|
||||
{
|
||||
throw new InvalidCastException($"Multiple values were specified for argument '{propertyName}', however it is not backed by an array or List<T>. Specify only one value.");
|
||||
}
|
||||
|
||||
convertedValue = ChangeType(value, propertyName, propertyType);
|
||||
}
|
||||
|
||||
// set the target properties' value to the converted value from the argument string
|
||||
property.SetValue(null, convertedValue);
|
||||
}
|
||||
}
|
||||
|
||||
PropertyInfo operandsProperty = GetOperandsProperty(type);
|
||||
|
||||
// check to ensure the target class has a property marked with the Operands attribute; if not GetOperandsProperty()
|
||||
// will return null.
|
||||
if (operandsProperty != default(PropertyInfo))
|
||||
{
|
||||
if (operandsProperty.PropertyType.IsAssignableFrom(typeof(List<string>)))
|
||||
{
|
||||
operandsProperty.SetValue(null, arguments.OperandList);
|
||||
}
|
||||
else
|
||||
{
|
||||
operandsProperty.SetValue(null, arguments.OperandList.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Converts the specified value for the specified argument to the specified Type.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to convert.</param>
|
||||
/// <param name="argument">The argument for which the value is being converted.</param>
|
||||
/// <param name="toType">The Type to which the value is being converted.</param>
|
||||
/// <returns>The converted value.</returns>
|
||||
private static object ChangeType(object value, string argument, Type toType)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ChangeType(value, toType);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// if the cast fails, throw an exception
|
||||
string message = $"Specified value '{value}' for argument '{argument}' (expected type: {toType}). ";
|
||||
message += "See inner exception for details.";
|
||||
|
||||
throw new ArgumentException(message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of each property in the specified dictionary to null.
|
||||
/// </summary>
|
||||
/// <param name="properties">The dictionary containing the properties to clear.</param>
|
||||
private static void ClearProperties(Dictionary<string, PropertyInfo> properties)
|
||||
{
|
||||
foreach (string key in properties.Keys)
|
||||
{
|
||||
properties[key].SetValue(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates and returns a dictionary containing the values specified in the command line arguments with which the
|
||||
/// application was started, keyed by argument name.
|
||||
/// </summary>
|
||||
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
|
||||
/// <returns>
|
||||
/// The dictionary containing the arguments and values specified in the command line arguments with which the
|
||||
/// application was started.
|
||||
/// </returns>
|
||||
private static Dictionary<string, object> GetArgumentDictionary(string commandLineString)
|
||||
{
|
||||
Dictionary<string, object> argumentDictionary = new Dictionary<string, object>();
|
||||
|
||||
foreach (Match match in Regex.Matches(commandLineString, ArgumentRegEx))
|
||||
{
|
||||
// the first match of the regular expression used to parse the string will contain the argument name, if one was matched.
|
||||
if (match.Groups[1].Value == default(string) || match.Groups[1].Value == string.Empty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string fullMatch = match.Groups[0].Value;
|
||||
string argument = match.Groups[1].Value;
|
||||
string value = match.Groups[2].Value;
|
||||
|
||||
value = TrimOuterQuotes(value);
|
||||
|
||||
// check to see if the argument uses a single dash. if so, split the argument name into a char array and add each
|
||||
// to the dictionary. if a value is specified, it belongs to the final character.
|
||||
if (Regex.IsMatch(fullMatch, GroupRegEx))
|
||||
{
|
||||
char[] charArray = argument.ToCharArray();
|
||||
|
||||
// iterate over the characters backwards to more easily assign the value
|
||||
for (int i = 0; i < charArray.Length; i++)
|
||||
{
|
||||
argumentDictionary.ExclusiveAdd(charArray[i].ToString(), i == charArray.Length - 1 ? value : string.Empty);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// add the argument and value to the dictionary if it doesn't already exist.
|
||||
argumentDictionary.ExclusiveAdd(argument, value);
|
||||
}
|
||||
}
|
||||
|
||||
return argumentDictionary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a dictionary containing properties in the target <see cref="Type"/> marked with the
|
||||
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/>, keyed on the string specified in the 'Name' field of the <see cref="Attribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="type">The <see cref="Type"/> for which the matching properties are to be retrieved.</param>
|
||||
/// <returns>
|
||||
/// A dictionary containing matching properties, keyed on the 'Name' field of the
|
||||
/// <see cref="ArgumentAttribute"/><see cref="Attribute"/> used to mark the property.
|
||||
/// </returns>
|
||||
private static Dictionary<string, PropertyInfo> GetArgumentProperties(Type type)
|
||||
{
|
||||
Dictionary<string, PropertyInfo> properties = new Dictionary<string, PropertyInfo>();
|
||||
|
||||
foreach (PropertyInfo property in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static))
|
||||
{
|
||||
// attempt to fetch the ArgumentAttribute of the property
|
||||
CustomAttributeData attribute = property.CustomAttributes.Where(a => a.AttributeType.Name == typeof(ArgumentAttribute).Name).FirstOrDefault();
|
||||
|
||||
// if found, extract the Name property and add it to the dictionary
|
||||
if (attribute != default(CustomAttributeData))
|
||||
{
|
||||
char shortName = (char)attribute.ConstructorArguments[0].Value;
|
||||
string longName = (string)attribute.ConstructorArguments[1].Value;
|
||||
|
||||
if (!properties.ContainsKey(shortName.ToString()) && !properties.ContainsKey(longName))
|
||||
{
|
||||
properties.Add(shortName.ToString(), property);
|
||||
properties.Add(longName, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates and returns a list containing the operands specified in the command line arguments with which the
|
||||
/// application was started.
|
||||
/// </summary>
|
||||
/// <param name="commandLineString">The command line arguments with which the application was started.</param>
|
||||
/// <returns>
|
||||
/// A list containing the operands specified in the command line arguments with which the application was started.
|
||||
/// </returns>
|
||||
private static List<string> GetOperandList(string commandLineString)
|
||||
{
|
||||
List<string> operands = new List<string>();
|
||||
|
||||
foreach (Match match in Regex.Matches(commandLineString, ArgumentRegEx))
|
||||
{
|
||||
// the 3rd match of the regular expression used to parse the string will contain the operand, if one was matched.
|
||||
if (match.Groups[3].Value == default(string) || match.Groups[3].Value == string.Empty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string fullMatch = match.Groups[0].Value;
|
||||
string operand = match.Groups[3].Value;
|
||||
|
||||
operands.Add(TrimOuterQuotes(operand));
|
||||
}
|
||||
|
||||
return operands;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates and returns a list containing the operands within the specified string grouped by whole words and groups
|
||||
/// of words contained within single or double quotes, treating strings that would otherwise be treated as argument
|
||||
/// keys as operands.
|
||||
/// </summary>
|
||||
/// <param name="operandListString">The string from which the list of operands is to be parsed.</param>
|
||||
/// <returns>
|
||||
/// A list containing the operands within the specified string grouped by whole words and groups of words contained
|
||||
/// within single or double quotes, treating strings that would otherwise be treated as argument keys as operands.
|
||||
/// </returns>
|
||||
private static List<string> GetOperandListStrict(string operandListString)
|
||||
{
|
||||
List<string> operands = new List<string>();
|
||||
|
||||
foreach (Match match in Regex.Matches(operandListString, OperandRegEx))
|
||||
{
|
||||
operands.Add(match.Groups[0].Value);
|
||||
}
|
||||
|
||||
return operands;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the property in the target <see cref="Type"/> marked with the
|
||||
/// <see cref="OperandsAttribute"/><see cref="Attribute"/>, if one exists.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The target property <see cref="Type"/> of the designated property must be of type string[] or List{string}.
|
||||
/// </remarks>
|
||||
/// <param name="type">The Type for which the matching property is to be retrieved.</param>
|
||||
/// <returns>The matching property, if one exists.</returns>
|
||||
/// <exception cref="InvalidCastException">
|
||||
/// Thrown when the Type of the retrieved property is not string[] or List{string}.
|
||||
/// </exception>
|
||||
private static PropertyInfo GetOperandsProperty(Type type)
|
||||
{
|
||||
PropertyInfo property = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
|
||||
.Where(p => p.CustomAttributes
|
||||
.Any(a => a.AttributeType.Name == typeof(OperandsAttribute).Name))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (property != default(PropertyInfo) && property.PropertyType != typeof(string[]) && property.PropertyType != typeof(List<string>))
|
||||
{
|
||||
throw new InvalidCastException("The target for the Operands attribute must be of string[] or List<string>.");
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the specified string with outer single or double quotes trimmed, if the string starts and ends with them.
|
||||
/// </summary>
|
||||
/// <param name="value">The string from which to trim outer single or double quotes.</param>
|
||||
/// <returns>The string with outer single or double quotes trimmed.</returns>
|
||||
private static string TrimOuterQuotes(string value)
|
||||
{
|
||||
if (value.StartsWith("\"") && value.EndsWith("\""))
|
||||
{
|
||||
value = value.Trim('"');
|
||||
}
|
||||
else if (value.StartsWith("'") && value.EndsWith("'"))
|
||||
{
|
||||
value = value.Trim('\'');
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the property is to be used as the target for automatic population of command line operands when invoking
|
||||
/// the <see cref="Arguments.Populate(string)"/> method.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
|
||||
public class OperandsAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<Costura Unmanaged32Assemblies="STDFUFiles.dll" />
|
||||
</Weavers>
|
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuild. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="DisableCompression" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="DisableCleanup" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="ExcludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="IncludeAssemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="PreloadOrder" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification on the target assembly after all weavers have been finished.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
|
@ -0,0 +1,244 @@
|
|||
//
|
||||
// Copyright (c) 2017 The nanoFramework project contributors
|
||||
// Portions Copyright (c) COPYRIGHT 2015 STMicroelectronics
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace nanoFramework.Tools
|
||||
{
|
||||
public class Hex2Dfu
|
||||
{
|
||||
|
||||
#region constants from STDFUFiles
|
||||
|
||||
/// <summary>
|
||||
/// No error.
|
||||
/// </summary>
|
||||
const uint STDFUFILES_NOERROR = 0x12340000;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
//a block of data to be written
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
unsafe public struct STDFUFILES_DfuImageElement
|
||||
{
|
||||
public UInt32 dwAddress;
|
||||
public UInt32 dwDataLength;
|
||||
public IntPtr Data;
|
||||
}
|
||||
|
||||
|
||||
#region imports from STDFUFiles.dll
|
||||
|
||||
// from dumpbin
|
||||
// 1 0 00004480 STDFUFILES_AppendImageToDFUFile
|
||||
// 2 1 000044E0 STDFUFILES_CloseDFUFile
|
||||
// 3 2 00004550 STDFUFILES_CreateImage
|
||||
// 4 3 000045B0 STDFUFILES_CreateImageFromMapping
|
||||
// 5 4 00004610 STDFUFILES_CreateNewDFUFile
|
||||
// 6 5 00004680 STDFUFILES_DestroyImage
|
||||
// 7 6 00004700 STDFUFILES_DestroyImageElement
|
||||
// 8 7 00004770 STDFUFILES_DuplicateImage
|
||||
// 9 8 00004820 STDFUFILES_FilterImageForOperation
|
||||
//10 9 000048A0 STDFUFILES_GetImageAlternate
|
||||
//11 A 00004900 STDFUFILES_GetImageElement
|
||||
//12 B 00004970 STDFUFILES_GetImageName
|
||||
//13 C 000049E0 STDFUFILES_GetImageNbElement
|
||||
//14 D 00004A40 STDFUFILES_GetImageSize
|
||||
//15 E 00004A90 STDFUFILES_ImageFromFile
|
||||
//16 F 00004B10 STDFUFILES_ImageToFile
|
||||
//17 10 00004B80 STDFUFILES_OpenExistingDFUFile
|
||||
//18 11 00004C20 STDFUFILES_ReadImageFromDFUFile
|
||||
//19 12 00004CA0 STDFUFILES_SetImageElement
|
||||
//20 13 00004D20 STDFUFILES_SetImageName
|
||||
|
||||
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_AppendImageToDFUFile", CharSet = CharSet.Auto)]
|
||||
public static extern UInt32 STDFUFILES_AppendImageToDFUFile(IntPtr handle, IntPtr image);
|
||||
|
||||
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_CloseDFUFile", CharSet = CharSet.Auto)]
|
||||
public static extern UInt32 STDFUFILES_CloseDFUFile(IntPtr handle);
|
||||
|
||||
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_CreateNewDFUFile", CharSet = CharSet.Auto)]
|
||||
public static extern UInt32 STDFUFILES_CreateNewDFUFile([MarshalAs(UnmanagedType.LPStr)]String szDevicePath, ref IntPtr handle, UInt16 Vid, UInt16 Pid, UInt16 Bcd);
|
||||
|
||||
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_CreateImage", CharSet = CharSet.Auto)]
|
||||
public static extern UInt32 STDFUFILES_CreateImage(ref IntPtr image, byte nAlternate);
|
||||
|
||||
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_DestroyImage", CharSet = CharSet.Auto)]
|
||||
public static extern UInt32 STDFUFILES_DestroyImage(ref IntPtr handle);
|
||||
|
||||
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_ImageFromFile", CharSet = CharSet.Auto)]
|
||||
public static extern UInt32 STDFUFILES_ImageFromFile([MarshalAs(UnmanagedType.LPStr)]String szDevicePath, ref IntPtr image, byte nAlternate);
|
||||
|
||||
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_SetImageElement", CharSet = CharSet.Auto)]
|
||||
public static extern UInt32 STDFUFILES_SetImageElement(IntPtr handle, UInt32 dwRank, bool bInsert, [MarshalAs(UnmanagedType.Struct)]STDFUFILES_DfuImageElement Element);
|
||||
|
||||
[DllImport("STDFUFiles.DLL", EntryPoint = "STDFUFILES_SetImageName", CharSet = CharSet.Auto)]
|
||||
public static extern UInt32 STDFUFILES_SetImageName(IntPtr image, [MarshalAs(UnmanagedType.LPStr)]String pPathFile);
|
||||
|
||||
#endregion
|
||||
|
||||
const UInt16 defaultSTMVid = 0x0483;
|
||||
const UInt16 defafultSTMPid = 0xDF11;
|
||||
const UInt16 defaultFwVersion = 0x2200;
|
||||
|
||||
public static bool CreateDfuFile(string hexFile, string dfuName, UInt16 vid = defaultSTMVid, UInt16 pid = defafultSTMPid, UInt16 fwVersion = defaultFwVersion)
|
||||
{
|
||||
IntPtr dfuFileHandle = (IntPtr)0;
|
||||
IntPtr imageFileHandle = (IntPtr)0;
|
||||
|
||||
// start creating a new DFU file for output
|
||||
var retCode = STDFUFILES_CreateNewDFUFile(dfuName, ref dfuFileHandle, vid, pid, fwVersion);
|
||||
|
||||
if (retCode == STDFUFILES_NOERROR)
|
||||
{
|
||||
|
||||
// get image from HEX file
|
||||
retCode = STDFUFILES_ImageFromFile(hexFile, ref imageFileHandle, 0);
|
||||
|
||||
if (retCode == STDFUFILES_NOERROR)
|
||||
{
|
||||
// add image of HEX file
|
||||
retCode = STDFUFILES_AppendImageToDFUFile(dfuFileHandle, imageFileHandle);
|
||||
|
||||
if (retCode != STDFUFILES_NOERROR)
|
||||
{
|
||||
// error adding this file
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"ERROR: adding {hexFile}");
|
||||
Console.WriteLine();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Adding image for {hexFile}");
|
||||
}
|
||||
}
|
||||
|
||||
// image file added, close DFU file
|
||||
STDFUFILES_CloseDFUFile(dfuFileHandle);
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"DFU generated: {dfuName}");
|
||||
Console.WriteLine($"Vendor ID: {vid.ToString("X4")}");
|
||||
Console.WriteLine($"Product ID: {pid.ToString("X4")}");
|
||||
Console.WriteLine($"Version: {fwVersion.ToString("X4")}");
|
||||
Console.WriteLine();
|
||||
|
||||
// clean-up
|
||||
if (retCode == STDFUFILES_NOERROR)
|
||||
{
|
||||
// destroy image
|
||||
STDFUFILES_DestroyImage(ref imageFileHandle);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CreateDfuFile(List<BinaryFileInfo> binFiles, string dfuName, UInt16 vid = defaultSTMVid, UInt16 pid = defafultSTMPid, UInt16 fwVersion = defaultFwVersion)
|
||||
{
|
||||
IntPtr dfuFileHandle = (IntPtr)0;
|
||||
IntPtr imageFileHandle = (IntPtr)0;
|
||||
|
||||
// start creating a new DFU file for output
|
||||
var retCode = STDFUFILES_CreateNewDFUFile(dfuName, ref dfuFileHandle, vid, pid, fwVersion);
|
||||
|
||||
if (retCode == STDFUFILES_NOERROR)
|
||||
{
|
||||
retCode = STDFUFILES_CreateImage(ref imageFileHandle, 0);
|
||||
|
||||
retCode = STDFUFILES_SetImageName(imageFileHandle, "nanoFramework");
|
||||
uint fileCounter = 0;
|
||||
|
||||
// loop through collection of bin files and add them
|
||||
foreach (BinaryFileInfo file in binFiles)
|
||||
{
|
||||
byte[] fileData = File.ReadAllBytes(file.FileName);
|
||||
|
||||
// get required memory size for byte array
|
||||
int size = Marshal.SizeOf(fileData[0]) * fileData.Length;
|
||||
|
||||
STDFUFILES_DfuImageElement element = new STDFUFILES_DfuImageElement();
|
||||
element.dwAddress = file.Address;
|
||||
element.dwDataLength = (uint)fileData.Length;
|
||||
|
||||
// allocate memory from the unmanaged memory
|
||||
element.Data = Marshal.AllocHGlobal(size);
|
||||
|
||||
// copy the byte array to the struct
|
||||
Marshal.Copy(fileData, 0, element.Data, fileData.Length);
|
||||
|
||||
// get image from HEX file
|
||||
retCode = STDFUFILES_SetImageElement(imageFileHandle, fileCounter++, true, element);
|
||||
|
||||
// free unmanaged memory
|
||||
Marshal.FreeHGlobal(element.Data);
|
||||
|
||||
if (retCode != STDFUFILES_NOERROR)
|
||||
{
|
||||
// error adding this file
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"ERROR: adding {file.FileName}");
|
||||
Console.WriteLine();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Adding file to image: {file.FileName}");
|
||||
}
|
||||
|
||||
// add image to DFU file
|
||||
retCode = STDFUFILES_AppendImageToDFUFile(dfuFileHandle, imageFileHandle);
|
||||
|
||||
if (retCode != STDFUFILES_NOERROR)
|
||||
{
|
||||
// error adding this file
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"ERROR: adding image to DFU file");
|
||||
Console.WriteLine();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// image file added, close DFU file
|
||||
STDFUFILES_CloseDFUFile(dfuFileHandle);
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"DFU generated: {dfuName}");
|
||||
Console.WriteLine($"Vendor ID: {vid.ToString("X4")}");
|
||||
Console.WriteLine($"Product ID: {pid.ToString("X4")}");
|
||||
Console.WriteLine($"Version: {fwVersion.ToString("X4")}");
|
||||
Console.WriteLine();
|
||||
|
||||
// clean-up
|
||||
if (retCode == STDFUFILES_NOERROR)
|
||||
{
|
||||
// destroy image
|
||||
STDFUFILES_DestroyImage(ref imageFileHandle);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class BinaryFileInfo
|
||||
{
|
||||
public string FileName { get; private set; }
|
||||
public uint Address { get; private set; }
|
||||
|
||||
public BinaryFileInfo(string fileName, uint address)
|
||||
{
|
||||
FileName = fileName;
|
||||
Address = address;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
//
|
||||
// Copyright (c) 2017 The nanoFramework project contributors
|
||||
// See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Utility.CommandLine;
|
||||
|
||||
namespace nanoFramework.Tools
|
||||
{
|
||||
class Program
|
||||
{
|
||||
[Argument('h', "hexfile")]
|
||||
private static string HexFile { get; set; }
|
||||
|
||||
[Argument('b', "binfile")]
|
||||
private static List<string> BinFiles { get; set; }
|
||||
|
||||
[Argument('a', "address")]
|
||||
private static List<string> Addresses { get; set; }
|
||||
|
||||
|
||||
[Argument('o', "outputdfu")]
|
||||
private static string OutputDfuFile { get; set; }
|
||||
|
||||
[Argument('v', "vid")]
|
||||
private static string Vid { get; set; }
|
||||
|
||||
[Argument('p', "pid")]
|
||||
private static string Pid { get; set; }
|
||||
|
||||
[Argument('f', "fwversion")]
|
||||
private static string FirmwareVersion { get; set; }
|
||||
|
||||
|
||||
private static ushort _Vid => ushort.Parse(Vid, System.Globalization.NumberStyles.HexNumber);
|
||||
private static ushort _Pid => ushort.Parse(Pid, System.Globalization.NumberStyles.HexNumber);
|
||||
private static ushort _FirmwareVersion => ushort.Parse(FirmwareVersion, System.Globalization.NumberStyles.HexNumber);
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Arguments.Populate();
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"nanoFramework HEX2DFU converter v{Assembly.GetExecutingAssembly().GetName().Version}");
|
||||
Console.WriteLine($"Copyright (c) 2017 nanoFramework project contributors");
|
||||
Console.WriteLine();
|
||||
|
||||
|
||||
// output usage help if no arguments are specified
|
||||
if (args.Count() == 0)
|
||||
{
|
||||
Console.WriteLine("Usage:");
|
||||
Console.WriteLine(" adding a single HEX file: hex2dfu -h=hex_file_name -o=output_DFU_image_file_name");
|
||||
Console.WriteLine(" adding one or more BIN files: hex2dfu -b=bin_file_name -a=address_to_flash [-b=bin_file_name_N -a=address_to_flash_N] -o=output_DFU_image_file_name");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" options:");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(@" [-v=""0000""] (VID of target USB device (hexadecimal format), leave empty to use STM default)");
|
||||
Console.WriteLine(@" [-p=""0000""] (PID of target USB device (hexadecimal format), leave empty to use STM default)");
|
||||
Console.WriteLine(@" [-f=""0000""] (Firmware version of the target USB device (hexadecimal format), leave empty to use default)");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
// args check
|
||||
|
||||
// need, at least, one hex file
|
||||
if (HexFile == null && BinFiles == null)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("ERROR: Need at least one HEX or BIN file to create DFU target image.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(@"Use -h=""path-to-hex-file"" for each HEX file to add to the DFU target.");
|
||||
Console.WriteLine(@"Use -b=bin_file_name -a=address_to_flash [-b=bin_file_name_N -a=address_to_flash_N] for each BIN file to add to the DFU target.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
if (BinFiles != null)
|
||||
{
|
||||
// need the addresses too
|
||||
if (Addresses == null)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("ERROR: For BIN files the addresses to flash are mandatory.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(@"Use -b=bin_file_name -a=address_to_flash [-b=bin_file_name_N -a=address_to_flash_N] for each BIN file to add to the DFU target.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
// output DFU file name is mandatory
|
||||
if (OutputDfuFile == null)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("ERROR: Output DFU target file name is required.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(@"Use -h=""path-to-dfu-file""");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
if (HexFile != null && OutputDfuFile != null)
|
||||
{
|
||||
// compose the call to CreateDfuFile according to the requested parameters
|
||||
if (Vid != null && Pid != null && FirmwareVersion != null)
|
||||
{
|
||||
Hex2Dfu.CreateDfuFile(HexFile, OutputDfuFile, _Vid, _Pid, _FirmwareVersion);
|
||||
}
|
||||
else if (Vid != null && Pid != null && FirmwareVersion == null)
|
||||
{
|
||||
Hex2Dfu.CreateDfuFile(HexFile, OutputDfuFile, _Vid, _Pid);
|
||||
}
|
||||
else if (Vid != null && Pid == null && FirmwareVersion == null)
|
||||
{
|
||||
Hex2Dfu.CreateDfuFile(HexFile, OutputDfuFile, _Vid);
|
||||
}
|
||||
else if (Vid == null && Pid == null && FirmwareVersion == null)
|
||||
{
|
||||
Hex2Dfu.CreateDfuFile(HexFile, OutputDfuFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (BinFiles != null && OutputDfuFile != null)
|
||||
{
|
||||
// combine BIN files and addresses
|
||||
List<BinaryFileInfo> binFiles = new List<BinaryFileInfo>();
|
||||
|
||||
var addressEnum = Addresses.GetEnumerator();
|
||||
|
||||
foreach (string file in BinFiles)
|
||||
{
|
||||
addressEnum.MoveNext();
|
||||
binFiles.Add(new BinaryFileInfo(file, uint.Parse(addressEnum.Current, System.Globalization.NumberStyles.HexNumber)));
|
||||
}
|
||||
|
||||
// compose the call to CreateDfuFile according to the requested parameters
|
||||
if (Vid != null && Pid != null && FirmwareVersion != null)
|
||||
{
|
||||
Hex2Dfu.CreateDfuFile(binFiles, OutputDfuFile, _Vid, _Pid, _FirmwareVersion);
|
||||
}
|
||||
else if (Vid != null && Pid != null && FirmwareVersion == null)
|
||||
{
|
||||
Hex2Dfu.CreateDfuFile(binFiles, OutputDfuFile, _Vid, _Pid);
|
||||
}
|
||||
else if (Vid != null && Pid == null && FirmwareVersion == null)
|
||||
{
|
||||
Hex2Dfu.CreateDfuFile(binFiles, OutputDfuFile, _Vid);
|
||||
}
|
||||
else if (Vid == null && Pid == null && FirmwareVersion == null)
|
||||
{
|
||||
Hex2Dfu.CreateDfuFile(binFiles, OutputDfuFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("nanoFramework Tools Hex2Dfu")]
|
||||
[assembly: AssemblyDescription("Utility to convert HEX files into DFU target image")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("nanoFramework project contributors")]
|
||||
[assembly: AssemblyProduct("nanoFramework Tools Hex2Dfu")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017 nanoFramework project contributors")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("378070ef-3572-47f4-a854-3d6c5da3eefa")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="packages\Costura.Fody.3.2.0\build\Costura.Fody.props" Condition="Exists('packages\Costura.Fody.3.2.0\build\Costura.Fody.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{378070EF-3572-47F4-A854-3D6C5DA3EEFA}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>nanoFramework.Tools.Hex2Dfu</RootNamespace>
|
||||
<AssemblyName>hex2dfu</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Costura, Version=3.2.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Costura.Fody.3.2.0\lib\net46\Costura.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Arguments.cs" />
|
||||
<Compile Include="Hex2Dfu.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="version.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="FodyWeavers.xml" />
|
||||
<EmbeddedResource Include="costura32\STDFUFiles.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.6">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft .NET Framework 4.6 %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="packages\Fody.3.3.2\build\Fody.targets" Condition="Exists('packages\Fody.3.3.2\build\Fody.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('packages\Fody.3.3.2\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Fody.3.3.2\build\Fody.targets'))" />
|
||||
<Error Condition="!Exists('packages\Costura.Fody.3.2.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.3.2.0\build\Costura.Fody.props'))" />
|
||||
<Error Condition="!Exists('packages\Nerdbank.GitVersioning.2.2.33\build\Nerdbank.GitVersioning.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Nerdbank.GitVersioning.2.2.33\build\Nerdbank.GitVersioning.targets'))" />
|
||||
</Target>
|
||||
<Import Project="packages\Nerdbank.GitVersioning.2.2.33\build\Nerdbank.GitVersioning.targets" Condition="Exists('packages\Nerdbank.GitVersioning.2.2.33\build\Nerdbank.GitVersioning.targets')" />
|
||||
</Project>
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26730.15
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "nanoFramework.Tools.Hex2Dfu", "nanoFramework.Tools.Hex2Dfu.csproj", "{378070EF-3572-47F4-A854-3D6C5DA3EEFA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{378070EF-3572-47F4-A854-3D6C5DA3EEFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{378070EF-3572-47F4-A854-3D6C5DA3EEFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{378070EF-3572-47F4-A854-3D6C5DA3EEFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{378070EF-3572-47F4-A854-3D6C5DA3EEFA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0CFE97F1-0501-4C1F-8CC5-11043784ECC5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Costura.Fody" version="3.2.0" targetFramework="net46" developmentDependency="true" />
|
||||
<package id="Fody" version="3.3.2" targetFramework="net46" developmentDependency="true" />
|
||||
<package id="Nerdbank.GitVersioning" version="2.2.33" targetFramework="net46" developmentDependency="true" />
|
||||
</packages>
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
|
||||
"version": "1.1",
|
||||
"assemblyVersion": {
|
||||
"precision": "revision"
|
||||
},
|
||||
"semVer1NumericIdentifierPadding": 3,
|
||||
"publicReleaseRefSpec": [
|
||||
"^refs/heads/master$",
|
||||
"^refs/heads/v\\d+(?:\\.\\d+)?$"
|
||||
],
|
||||
"cloudBuild": {
|
||||
"setVersionVariables": true,
|
||||
"setAllVariables": true
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче