mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-05 03:21:40 +00:00
Compare commits
112 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72717cecf0 | ||
|
|
971ff3ac40 | ||
|
|
b80e436f02 | ||
|
|
be1a053cbe | ||
|
|
f4555dc545 | ||
|
|
54fdd1db51 | ||
|
|
1805785cc6 | ||
|
|
e62f6419b5 | ||
|
|
fa7824c616 | ||
|
|
9090aa6bcc | ||
|
|
5655ca6890 | ||
|
|
50fdfd8bce | ||
|
|
3120a6439b | ||
|
|
ab3e8c8db7 | ||
|
|
5144819ce2 | ||
|
|
d779fe23f0 | ||
|
|
b2a3f34433 | ||
|
|
b09a6d6a2d | ||
|
|
9893cf1f7e | ||
|
|
fc91daf397 | ||
|
|
a3e205cb6f | ||
|
|
553bed32b5 | ||
|
|
6c91feaf3f | ||
|
|
4ddb9aa08f | ||
|
|
4aadebdbb2 | ||
|
|
da8d70f887 | ||
|
|
80a0d8de1c | ||
|
|
3ad476bc28 | ||
|
|
e6d8e05b91 | ||
|
|
46fa17dfd8 | ||
|
|
43c35286f3 | ||
|
|
3d317f7035 | ||
|
|
a161bd5be9 | ||
|
|
0f730fc28d | ||
|
|
12e06b09c3 | ||
|
|
641101f574 | ||
|
|
6a1201432c | ||
|
|
e77a06bfa6 | ||
|
|
8b0b18bd07 | ||
|
|
1766f3bf0f | ||
|
|
4578fa756c | ||
|
|
d6e1e28fc2 | ||
|
|
49048c3998 | ||
|
|
8b079d9b20 | ||
|
|
1522adaa0e | ||
|
|
3cd57b8b43 | ||
|
|
c944967476 | ||
|
|
dbd631da61 | ||
|
|
f731ae37d2 | ||
|
|
0a8da1a0bd | ||
|
|
be5f0880c8 | ||
|
|
a02cd4a50e | ||
|
|
efd31543f6 | ||
|
|
a151f23319 | ||
|
|
822811c853 | ||
|
|
23834c87f4 | ||
|
|
f103a6b712 | ||
|
|
3257736ffa | ||
|
|
9df25eda88 | ||
|
|
5a13739818 | ||
|
|
5ca39e7f84 | ||
|
|
ffe34f00fe | ||
|
|
a5cc0808c4 | ||
|
|
08fafe2607 | ||
|
|
a2af7d9273 | ||
|
|
a731c7a8db | ||
|
|
7e74da5cff | ||
|
|
0977fd0dff | ||
|
|
3241ef7b1b | ||
|
|
f922466d41 | ||
|
|
243f06da2d | ||
|
|
44e91a184d | ||
|
|
e6b0f398b6 | ||
|
|
5a475e1071 | ||
|
|
f8def88e4d | ||
|
|
db09e5209f | ||
|
|
9fdd945a52 | ||
|
|
00b8e7d1c5 | ||
|
|
798b8e398a | ||
|
|
affb27038b | ||
|
|
6767781a41 | ||
|
|
6007cc752d | ||
|
|
9cf5c77d69 | ||
|
|
9dc5481d1c | ||
|
|
3948650e6c | ||
|
|
49fcdb64ed | ||
|
|
1e715ce4bb | ||
|
|
f9fd7a0b45 | ||
|
|
e9a3c2d1b8 | ||
|
|
129575dd23 | ||
|
|
ba8d2691fc | ||
|
|
f3d3a59ca0 | ||
|
|
b653fc7db1 | ||
|
|
71ee03a531 | ||
|
|
4a2493ff2e | ||
|
|
0b20111824 | ||
|
|
449977e63b | ||
|
|
b0504cbef5 | ||
|
|
fccb395564 | ||
|
|
b510417541 | ||
|
|
0330467874 | ||
|
|
4c15a46cda | ||
|
|
d59f8d1227 | ||
|
|
bbc8a3137b | ||
|
|
951c038f19 | ||
|
|
1b0c5af86e | ||
|
|
a113bd4192 | ||
|
|
d3c23345da | ||
|
|
2e1b3d0f83 | ||
|
|
58b39f47aa | ||
|
|
dc0f8cf296 | ||
|
|
3d34d1ca40 |
167
.clang-format
Normal file
167
.clang-format
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: Google
|
||||||
|
AccessModifierOffset: -1
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveMacros: false
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllConstructorInitializersOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DeriveLineEnding: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^<ext/.*\.h>'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
- Regex: '^<.*\.h>'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
- Regex: '^<.*'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Never
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 1
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 200
|
||||||
|
PointerAlignment: Left
|
||||||
|
RawStringFormats:
|
||||||
|
- Language: Cpp
|
||||||
|
Delimiters:
|
||||||
|
- cc
|
||||||
|
- CC
|
||||||
|
- cpp
|
||||||
|
- Cpp
|
||||||
|
- CPP
|
||||||
|
- 'c++'
|
||||||
|
- 'C++'
|
||||||
|
CanonicalDelimiter: ''
|
||||||
|
BasedOnStyle: google
|
||||||
|
- Language: TextProto
|
||||||
|
Delimiters:
|
||||||
|
- pb
|
||||||
|
- PB
|
||||||
|
- proto
|
||||||
|
- PROTO
|
||||||
|
EnclosingFunctions:
|
||||||
|
- EqualsProto
|
||||||
|
- EquivToProto
|
||||||
|
- PARSE_PARTIAL_TEXT_PROTO
|
||||||
|
- PARSE_TEST_PROTO
|
||||||
|
- PARSE_TEXT_PROTO
|
||||||
|
- ParseTextOrDie
|
||||||
|
- ParseTextProtoOrDie
|
||||||
|
CanonicalDelimiter: ''
|
||||||
|
BasedOnStyle: google
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
Standard: Auto
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 8
|
||||||
|
UseCRLF: false
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -1,3 +1,2 @@
|
|||||||
# These owners will be the default owners for everything in the repo.
|
# These owners will be the default owners for everything in the repo.
|
||||||
* @PhotonVision/program-devs
|
* @PhotonVision/program-devs
|
||||||
|
|
||||||
|
|||||||
285
.github/workflows/main.yml
vendored
285
.github/workflows/main.yml
vendored
@@ -14,7 +14,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# This job builds the client (web view).
|
# This job builds the client (web view).
|
||||||
build-client:
|
photonclient-build:
|
||||||
|
|
||||||
# Let all steps run within the photon-client dir.
|
# Let all steps run within the photon-client dir.
|
||||||
defaults:
|
defaults:
|
||||||
@@ -49,12 +49,7 @@ jobs:
|
|||||||
name: built-client
|
name: built-client
|
||||||
path: photon-client/dist/
|
path: photon-client/dist/
|
||||||
|
|
||||||
build-server:
|
photon-build-all:
|
||||||
# Let all steps run within the photon-server dir.
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: photon-server
|
|
||||||
|
|
||||||
# The type of runner that the job will run on.
|
# The type of runner that the job will run on.
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
@@ -63,6 +58,10 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
# Fetch tags.
|
||||||
|
- name: Fetch tags
|
||||||
|
run: git fetch --tags --force
|
||||||
|
|
||||||
# Install Java 11.
|
# Install Java 11.
|
||||||
- name: Install Java 11
|
- name: Install Java 11
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v1
|
||||||
@@ -73,19 +72,28 @@ jobs:
|
|||||||
- name: Gradle Build
|
- name: Gradle Build
|
||||||
run: |
|
run: |
|
||||||
chmod +x gradlew
|
chmod +x gradlew
|
||||||
./gradlew build -x check
|
./gradlew build -x check --max-workers 1
|
||||||
|
|
||||||
# Run Tests Generate Coverage Report.
|
# Run Gradle Tests.
|
||||||
- name: Gradle Test and Coverage
|
- name: Gradle Tests
|
||||||
run: ./gradlew jacocoTestReport
|
run: ./gradlew testHeadless -i --max-workers 1
|
||||||
|
|
||||||
|
# Generate Coverage Report.
|
||||||
|
- name: Gradle Coverage
|
||||||
|
run: ./gradlew jacocoTestReport --max-workers 1
|
||||||
|
|
||||||
# Publish Coverage Report.
|
# Publish Coverage Report.
|
||||||
- name: Publish Coverage Report
|
- name: Publish Server Coverage Report
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v1
|
||||||
with:
|
with:
|
||||||
file: ./photon-server/build/reports/jacoco/test/jacocoTestReport.xml
|
file: ./photon-server/build/reports/jacoco/test/jacocoTestReport.xml
|
||||||
|
|
||||||
build-offline-docs:
|
- name: Publish Core Coverage Report
|
||||||
|
uses: codecov/codecov-action@v1
|
||||||
|
with:
|
||||||
|
file: ./photon-core/build/reports/jacoco/test/jacocoTestReport.xml
|
||||||
|
|
||||||
|
photonserver-build-offline-docs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -121,75 +129,7 @@ jobs:
|
|||||||
name: built-docs
|
name: built-docs
|
||||||
path: build/html
|
path: build/html
|
||||||
|
|
||||||
build-package:
|
photonserver-check-lint:
|
||||||
needs: [build-client, build-server, build-offline-docs]
|
|
||||||
|
|
||||||
# Let all steps run within the photon-server dir.
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: photon-server
|
|
||||||
|
|
||||||
# The type of runner that the job will run on.
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# Checkout code.
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
|
|
||||||
# Install Java 11.
|
|
||||||
- uses: actions/setup-java@v1
|
|
||||||
with:
|
|
||||||
java-version: 11
|
|
||||||
|
|
||||||
# Clear any existing web resources.
|
|
||||||
- run: |
|
|
||||||
rm -rf src/main/resources/web/*
|
|
||||||
mkdir -p src/main/resources/web/docs
|
|
||||||
|
|
||||||
# Download client artifact to resources folder.
|
|
||||||
- uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: built-client
|
|
||||||
path: photon-server/src/main/resources/web/
|
|
||||||
|
|
||||||
# Download docs artifact to resources folder.
|
|
||||||
- uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: built-docs
|
|
||||||
path: photon-server/src/main/resources/web/docs
|
|
||||||
|
|
||||||
|
|
||||||
# Print folder contents.
|
|
||||||
- run: ls
|
|
||||||
working-directory: photon-server/src/main/resources/web/
|
|
||||||
|
|
||||||
# Build fat jar.
|
|
||||||
- run: |
|
|
||||||
chmod +x gradlew
|
|
||||||
./gradlew shadowJar
|
|
||||||
working-directory: photon-server
|
|
||||||
|
|
||||||
# Upload final fat jar as artifact.
|
|
||||||
- uses: actions/upload-artifact@master
|
|
||||||
with:
|
|
||||||
name: jar
|
|
||||||
path: photon-server/build/libs
|
|
||||||
|
|
||||||
- uses: eine/tip@master
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
tag: 'Dev'
|
|
||||||
rm: true
|
|
||||||
files: |
|
|
||||||
photon-server/build/libs/*.jar
|
|
||||||
if: github.event_name == 'push'
|
|
||||||
|
|
||||||
check-lint:
|
|
||||||
# Let all steps run within the photon-server dir.
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: photon-server
|
|
||||||
|
|
||||||
# The type of runner that the job will run on.
|
# The type of runner that the job will run on.
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
@@ -207,14 +147,189 @@ jobs:
|
|||||||
chmod +x gradlew
|
chmod +x gradlew
|
||||||
./gradlew spotlessCheck
|
./gradlew spotlessCheck
|
||||||
|
|
||||||
release:
|
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
|
||||||
needs: [build-package]
|
# Building photonlib
|
||||||
|
photonlib-build-host:
|
||||||
|
env:
|
||||||
|
MACOSX_DEPLOYMENT_TARGET: 10.14
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: windows-latest
|
||||||
|
artifact-name: Win64
|
||||||
|
- os: macos-latest
|
||||||
|
artifact-name: macOS
|
||||||
|
- os: ubuntu-latest
|
||||||
|
artifact-name: Linux
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
name: "Photonlib - Build - ${{ matrix.artifact-name }}"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2.3.4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
- run: git fetch --tags --force
|
||||||
|
- run: |
|
||||||
|
chmod +x gradlew
|
||||||
|
./gradlew photon-lib:build --max-workers 1
|
||||||
|
- run: ./gradlew photon-lib:publish photon-targeting:publish
|
||||||
|
name: Publish
|
||||||
|
env:
|
||||||
|
ARTIFACTORY_API_KEY: ${{ secrets.ARTIFACTORY_API_KEY }}
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
|
||||||
|
photonlib-build-docker:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- container: wpilib/roborio-cross-ubuntu:2022-18.04
|
||||||
|
artifact-name: Athena
|
||||||
|
- container: wpilib/raspbian-cross-ubuntu:10-18.04
|
||||||
|
artifact-name: Raspbian
|
||||||
|
- container: wpilib/aarch64-cross-ubuntu:bionic-18.04
|
||||||
|
artifact-name: Aarch64
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: ${{ matrix.container }}
|
||||||
|
name: "Photonlib - Build - ${{ matrix.artifact-name }}"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2.3.4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
- run: |
|
||||||
|
chmod +x gradlew
|
||||||
|
./gradlew photon-lib:build --max-workers 1
|
||||||
|
- run: |
|
||||||
|
chmod +x gradlew
|
||||||
|
./gradlew photon-lib:publish
|
||||||
|
env:
|
||||||
|
ARTIFACTORY_API_KEY: ${{ secrets.ARTIFACTORY_API_KEY }}
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
|
||||||
|
photonlib-wpiformat:
|
||||||
|
name: "wpiformat"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Fetch all history and metadata
|
||||||
|
run: |
|
||||||
|
git fetch --prune --unshallow
|
||||||
|
git checkout -b pr
|
||||||
|
git branch -f master origin/master
|
||||||
|
- name: Set up Python 3.8
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
- name: Install clang-format
|
||||||
|
run: |
|
||||||
|
sudo sh -c "echo 'deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs)-proposed restricted main multiverse universe' >> /etc/apt/sources.list.d/proposed-repositories.list"
|
||||||
|
sudo apt-get update -q
|
||||||
|
sudo apt-get install -y clang-format-12
|
||||||
|
- name: Install wpiformat
|
||||||
|
run: pip3 install wpiformat
|
||||||
|
- name: Run
|
||||||
|
run: wpiformat -clang 12
|
||||||
|
- name: Check Output
|
||||||
|
run: git --no-pager diff --exit-code HEAD
|
||||||
|
- name: Generate diff
|
||||||
|
run: git diff HEAD > wpiformat-fixes.patch
|
||||||
|
if: ${{ failure() }}
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: wpiformat fixes
|
||||||
|
path: wpiformat-fixes.patch
|
||||||
|
if: ${{ failure() }}
|
||||||
|
|
||||||
|
photon-build-package:
|
||||||
|
needs: [photonclient-build, photon-build-all, photonserver-build-offline-docs, photonlib-build-host, photonlib-build-docker]
|
||||||
|
|
||||||
|
# The type of runner that the job will run on.
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Checkout code.
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
|
||||||
|
# Install Java 11.
|
||||||
|
- uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 11
|
||||||
|
|
||||||
|
# Clear any existing web resources.
|
||||||
|
- run: |
|
||||||
|
rm -rf photon-server/src/main/resources/web/*
|
||||||
|
mkdir -p photon-server/src/main/resources/web/docs
|
||||||
|
|
||||||
|
# Download client artifact to resources folder.
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: built-client
|
||||||
|
path: photon-server/src/main/resources/web/
|
||||||
|
|
||||||
|
# Download docs artifact to resources folder.
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: built-docs
|
||||||
|
path: photon-server/src/main/resources/web/docs
|
||||||
|
|
||||||
|
# Build fat jar for both pi and everything
|
||||||
|
- run: |
|
||||||
|
chmod +x gradlew
|
||||||
|
./gradlew photon-server:shadowJar --max-workers 1
|
||||||
|
./gradlew photon-server:shadowJar --max-workers 1 -Ppionly
|
||||||
|
|
||||||
|
# The image will only pull the Pi JAR in
|
||||||
|
- name: Generate image
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/generatePiImage.sh
|
||||||
|
./scripts/generatePiImage.sh
|
||||||
|
|
||||||
|
# Upload final fat jar as artifact.
|
||||||
|
- uses: actions/upload-artifact@master
|
||||||
|
with:
|
||||||
|
name: jar
|
||||||
|
path: photon-server/build/libs
|
||||||
|
- uses: actions/upload-artifact@master
|
||||||
|
with:
|
||||||
|
name: image
|
||||||
|
path: photonvision*.zip
|
||||||
|
|
||||||
|
- uses: pyTooling/Actions/releaser@r0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tag: 'Dev'
|
||||||
|
rm: true
|
||||||
|
files: |
|
||||||
|
photon-server/build/libs/*.jar
|
||||||
|
photonvision*.zip
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
|
||||||
|
photon-release:
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
needs: [photon-build-package]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# This *should* pull in fat and pi-only jars
|
||||||
- uses: actions/download-artifact@v2
|
- uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: jar
|
name: jar
|
||||||
|
|
||||||
|
# And the image we made previously
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: image
|
||||||
|
|
||||||
|
# All we've downloaded (ideally) is the fat jar, pi jar, and image. So just upload it all
|
||||||
- uses: softprops/action-gh-release@v1
|
- uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
files: '**/*'
|
files: '**/*'
|
||||||
|
|||||||
36
.gitignore
vendored
36
.gitignore
vendored
@@ -104,17 +104,25 @@ fabric.properties
|
|||||||
# Android studio 3.1+ serialized cache file
|
# Android studio 3.1+ serialized cache file
|
||||||
.idea/caches/build_file_checksums.ser
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
# Temporary build files
|
||||||
photon-server/.gradle
|
**/.gradle
|
||||||
photon-server/target
|
**/target
|
||||||
photon-server/src/main/java/META-INF
|
**/src/main/java/META-INF
|
||||||
photon-server/.settings
|
**/.settings
|
||||||
photon-server/.classpath
|
**/.classpath
|
||||||
photon-server/.project
|
**/.project
|
||||||
photon-server/settings
|
**/settings
|
||||||
photon-server/dependency-reduced-pom.xml
|
**/dependency-reduced-pom.xml
|
||||||
# photon-server/photon-vision.iml
|
# photon-server/photon-vision.iml
|
||||||
|
|
||||||
|
# compile_commands
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
|
# clang configuration and clangd cache
|
||||||
|
.clang
|
||||||
|
.clangd/
|
||||||
|
.cache/
|
||||||
|
|
||||||
New client/photon-client/*
|
New client/photon-client/*
|
||||||
|
|
||||||
*.prefs
|
*.prefs
|
||||||
@@ -126,3 +134,13 @@ photon-server/photon-vision
|
|||||||
photon-server/src/main/resources/web
|
photon-server/src/main/resources/web
|
||||||
photon-server/src/main/java/org/photonvision/PhotonVersion.java
|
photon-server/src/main/java/org/photonvision/PhotonVersion.java
|
||||||
photon-server/src/main/generated/native/include/org_photonvision_raspi_PicamJNI.h
|
photon-server/src/main/generated/native/include/org_photonvision_raspi_PicamJNI.h
|
||||||
|
*.bin
|
||||||
|
.gradle
|
||||||
|
.gradle/*
|
||||||
|
photonvision_config
|
||||||
|
build/spotlessJava
|
||||||
|
build/*
|
||||||
|
build
|
||||||
|
photon-lib/src/main/java/org/photonvision/PhotonVersion.java
|
||||||
|
/photonlib-java-examples/bin/
|
||||||
|
photon-lib/src/generate/native/include/PhotonVersion.h
|
||||||
|
|||||||
27
.styleguide
Normal file
27
.styleguide
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
cppHeaderFileInclude {
|
||||||
|
\.h$
|
||||||
|
\.hpp$
|
||||||
|
\.inc$
|
||||||
|
\.inl$
|
||||||
|
}
|
||||||
|
|
||||||
|
cppSrcFileInclude {
|
||||||
|
\.cpp$
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiableFileExclude {
|
||||||
|
\.jpg$
|
||||||
|
\.png$
|
||||||
|
\.so$
|
||||||
|
}
|
||||||
|
|
||||||
|
includeProject {
|
||||||
|
^photonLib/
|
||||||
|
}
|
||||||
|
|
||||||
|
includeOtherLibs {
|
||||||
|
^frc/
|
||||||
|
^networktables/
|
||||||
|
^units/
|
||||||
|
^wpi/
|
||||||
|
}
|
||||||
@@ -14,4 +14,3 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
17
README.md
17
README.md
@@ -10,8 +10,17 @@ If you are interested in contributing code or documentation to the project, plea
|
|||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
A list of contributors is available in our documentation on ReadTheDocs.
|
<a href="https://github.com/PhotonVision/photonvision/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=PhotonVision/photonvision" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## Gradle Arguments
|
||||||
|
|
||||||
|
Note that these are case sensitive!
|
||||||
|
|
||||||
|
* `-Ppionly`: only builds for `linuxraspbian`, which reduces JAR size. The JAR name will have "-raspi" appended.
|
||||||
|
- `-PtgtIp`: deploys (builds and copies the JAR) to the coprocessor at the specified IP
|
||||||
|
- `-Pprofile`: enables JVM profiling
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
PhotonVision was forked from [Chameleon Vision](https://github.com/Chameleon-Vision/chameleon-vision/). Thank you to everyone who worked on the original project.
|
PhotonVision was forked from [Chameleon Vision](https://github.com/Chameleon-Vision/chameleon-vision/). Thank you to everyone who worked on the original project.
|
||||||
@@ -29,3 +38,9 @@ PhotonVision was forked from [Chameleon Vision](https://github.com/Chameleon-Vis
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
PhotonVision is licensed under the [GNU General Public License](https://www.gnu.org/licenses/gpl-3.0.html)
|
PhotonVision is licensed under the [GNU General Public License](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||||
|
|
||||||
|
## Meeting Notes
|
||||||
|
Our meeting notes can be found in the wiki section of this repository.
|
||||||
|
|
||||||
|
* [2020 Meeting Notes](https://github.com/PhotonVision/photonvision/wiki/2020-Meeting-Notes)
|
||||||
|
* [2021 Meeting Notes](https://github.com/PhotonVision/photonvision/wiki/2021-Meeting-Notes)
|
||||||
|
|||||||
53
build.gradle
Normal file
53
build.gradle
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
plugins {
|
||||||
|
id "com.diffplug.spotless" version "6.1.2"
|
||||||
|
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||||
|
id "com.github.node-gradle.node" version "3.1.1" apply false
|
||||||
|
id "edu.wpi.first.GradleJni" version "1.0.0"
|
||||||
|
id "edu.wpi.first.GradleVsCode" version "1.1.0"
|
||||||
|
id "edu.wpi.first.NativeUtils" version "2022.8.1" apply false
|
||||||
|
id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2"
|
||||||
|
id "org.hidetake.ssh" version "2.10.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
maven { url = "https://maven.photonvision.org/repository/internal/" }
|
||||||
|
}
|
||||||
|
wpilibRepositories.addAllReleaseRepositories(it)
|
||||||
|
wpilibRepositories.addAllDevelopmentRepositories(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the version number.
|
||||||
|
apply from: "versioningHelper.gradle"
|
||||||
|
|
||||||
|
ext {
|
||||||
|
wpilibVersion = "2022.1.1"
|
||||||
|
opencvVersion = "4.5.2-1"
|
||||||
|
joglVersion = "2.4.0-rc-20200307"
|
||||||
|
pubVersion = versionString
|
||||||
|
isDev = pubVersion.startsWith("dev")
|
||||||
|
|
||||||
|
|
||||||
|
jniPlatforms = project.hasProperty('pionly') ? ['linuxraspbian']
|
||||||
|
: ['linuxaarch64bionic', 'linuxraspbian', 'linuxx86-64', 'osxx86-64', 'windowsx86-64']
|
||||||
|
|
||||||
|
println("Building for archs " + jniPlatforms)
|
||||||
|
}
|
||||||
|
|
||||||
|
spotless {
|
||||||
|
java {
|
||||||
|
toggleOffOn()
|
||||||
|
googleJavaFormat()
|
||||||
|
indentWithTabs(2)
|
||||||
|
indentWithSpaces(4)
|
||||||
|
removeUnusedImports()
|
||||||
|
trimTrailingWhitespace()
|
||||||
|
endWithNewline()
|
||||||
|
}
|
||||||
|
java {
|
||||||
|
target "**/*.java"
|
||||||
|
targetExclude("photon-core/src/main/java/org/photonvision/PhotonVersion.java")
|
||||||
|
targetExclude("photon-lib/src/main/java/org/photonvision/PhotonVersion.java")
|
||||||
|
}
|
||||||
|
}
|
||||||
8
gradle.properties
Normal file
8
gradle.properties
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# The --add-exports flags work around a bug with spotless and JDK 17
|
||||||
|
# https://github.com/diffplug/spotless/issues/834
|
||||||
|
org.gradle.jvmargs= \
|
||||||
|
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
|
||||||
|
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
|
||||||
|
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
|
||||||
|
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
|
||||||
|
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
|
||||||
Binary file not shown.
@@ -1,6 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
||||||
distributionSha256Sum=5a3578b9f0bb162f5e08cf119f447dfb8fa950cedebb4d2a977e912a11a74b91
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
2
photon-server/gradlew → gradlew
vendored
2
photon-server/gradlew → gradlew
vendored
@@ -82,6 +82,7 @@ esac
|
|||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
@@ -129,6 +130,7 @@ fi
|
|||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
25
photon-server/gradlew.bat → gradlew.bat
vendored
25
photon-server/gradlew.bat → gradlew.bat
vendored
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
|||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
|||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
@@ -51,7 +54,7 @@ goto fail
|
|||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
@@ -61,28 +64,14 @@ echo location of your Java installation.
|
|||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windows variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
420
photon-client/package-lock.json
generated
420
photon-client/package-lock.json
generated
@@ -2118,16 +2118,6 @@
|
|||||||
"integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==",
|
"integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/mini-css-extract-plugin": {
|
|
||||||
"version": "0.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.1.tgz",
|
|
||||||
"integrity": "sha512-+mN04Oszdz9tGjUP/c1ReVwJXxSniLd7lF++sv+8dkABxVNthg6uccei+4ssKxRHGoMmPxdn7uBdJWONSJGTGQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/webpack": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/minimatch": {
|
"@types/minimatch": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||||
@@ -2164,6 +2154,12 @@
|
|||||||
"integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==",
|
"integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/raf": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"@types/range-parser": {
|
"@types/range-parser": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
|
||||||
@@ -2679,17 +2675,6 @@
|
|||||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ansi-styles": {
|
|
||||||
"version": "4.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
|
||||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/color-name": "^1.1.1",
|
|
||||||
"color-convert": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"version": "4.14.0",
|
"version": "4.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.0.tgz",
|
||||||
@@ -2734,23 +2719,6 @@
|
|||||||
"integrity": "sha512-Hpwa4obv7EGP+TjkCh/wVvbtNJewxmtg4yVJBLFnxo35vbPapBr138bUWENkb5j5L9JZJ9RXLn4OrXRG/cecPQ==",
|
"integrity": "sha512-Hpwa4obv7EGP+TjkCh/wVvbtNJewxmtg4yVJBLFnxo35vbPapBr138bUWENkb5j5L9JZJ9RXLn4OrXRG/cecPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"color-convert": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"color-name": "~1.1.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"color-name": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.3.554",
|
"version": "1.3.554",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.554.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.554.tgz",
|
||||||
@@ -2784,13 +2752,6 @@
|
|||||||
"path-exists": "^4.0.0"
|
"path-exists": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"has-flag": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"locate-path": {
|
"locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
@@ -2924,16 +2885,6 @@
|
|||||||
"ansi-regex": "^5.0.0"
|
"ansi-regex": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"supports-color": {
|
|
||||||
"version": "7.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
|
||||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"has-flag": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"terser-webpack-plugin": {
|
"terser-webpack-plugin": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz",
|
||||||
@@ -2960,34 +2911,6 @@
|
|||||||
"psl": "^1.1.28",
|
"psl": "^1.1.28",
|
||||||
"punycode": "^2.1.1"
|
"punycode": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"vue-loader-v16": {
|
|
||||||
"version": "npm:vue-loader@16.0.0-beta.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.5.tgz",
|
|
||||||
"integrity": "sha512-ciWfzNefqWlmzKznCWY9hl+fPP4KlQ0A9MtHbJ/8DpyY+dAM8gDrjufIdxwTgC4szE4EZC3A6ip/BbrqM84GqA==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"@types/mini-css-extract-plugin": "^0.9.1",
|
|
||||||
"chalk": "^3.0.0",
|
|
||||||
"hash-sum": "^2.0.0",
|
|
||||||
"loader-utils": "^1.2.3",
|
|
||||||
"merge-source-map": "^1.1.0",
|
|
||||||
"source-map": "^0.6.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"chalk": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"ansi-styles": "^4.1.0",
|
|
||||||
"supports-color": "^7.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -3559,8 +3482,7 @@
|
|||||||
"atob": {
|
"atob": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"autoprefixer": {
|
"autoprefixer": {
|
||||||
"version": "9.8.6",
|
"version": "9.8.6",
|
||||||
@@ -3819,6 +3741,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"base64-arraybuffer": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"base64-js": {
|
"base64-js": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||||
@@ -4110,6 +4038,11 @@
|
|||||||
"node-releases": "^1.1.44"
|
"node-releases": "^1.1.44"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"btoa": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
|
||||||
|
},
|
||||||
"buffer": {
|
"buffer": {
|
||||||
"version": "4.9.2",
|
"version": "4.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
|
||||||
@@ -4390,6 +4323,45 @@
|
|||||||
"integrity": "sha512-6ljkLtF1KM5fQ+5ZN0wuyVvvebJxgJPTmScOMaFuQN2QuOzvRJnWSKfzQskQU5IOU4Gap3zasYPIinzwUjoj/g==",
|
"integrity": "sha512-6ljkLtF1KM5fQ+5ZN0wuyVvvebJxgJPTmScOMaFuQN2QuOzvRJnWSKfzQskQU5IOU4Gap3zasYPIinzwUjoj/g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"canvg": {
|
||||||
|
"version": "3.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.9.tgz",
|
||||||
|
"integrity": "sha512-rDXcnRPuz4QHoCilMeoTxql+fvGqNAxp+qV/KHD8rOiJSAfVjFclbdUNHD2Uqfthr+VMg17bD2bVuk6F07oLGw==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.12.5",
|
||||||
|
"@types/raf": "^3.4.0",
|
||||||
|
"core-js": "^3.8.3",
|
||||||
|
"raf": "^3.4.1",
|
||||||
|
"regenerator-runtime": "^0.13.7",
|
||||||
|
"rgbcolor": "^1.0.1",
|
||||||
|
"stackblur-canvas": "^2.0.0",
|
||||||
|
"svg-pathdata": "^6.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": {
|
||||||
|
"version": "7.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.0.tgz",
|
||||||
|
"integrity": "sha512-Nht8L0O8YCktmsDV6FqFue7vQLRx3Hb0B37lS5y0jDRqRxlBG4wIJHnf9/bgSE2UyipKFA01YtS+npRdTWBUyw==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"regenerator-runtime": "^0.13.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"core-js": {
|
||||||
|
"version": "3.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.0.tgz",
|
||||||
|
"integrity": "sha512-L1TpFRWXZ76vH1yLM+z6KssLZrP8Z6GxxW4auoCj+XiViOzNPJCAuTIkn03BGdFe6Z5clX5t64wRIRypsZQrUg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"regenerator-runtime": {
|
||||||
|
"version": "0.13.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
||||||
|
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"case-sensitive-paths-webpack-plugin": {
|
"case-sensitive-paths-webpack-plugin": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz",
|
||||||
@@ -5172,6 +5144,15 @@
|
|||||||
"timsort": "^0.3.0"
|
"timsort": "^0.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"css-line-break": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-gwKYIMUn7xodIcb346wgUhE2Dt5O1Kmrc16PWi8sL4FTfyDj8P5095rzH7+O8CTZudJr+uw2GCI/hwEkDJFI2w==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"base64-arraybuffer": "^0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"css-loader": {
|
"css-loader": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
|
||||||
@@ -5809,6 +5790,12 @@
|
|||||||
"domelementtype": "1"
|
"domelementtype": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dompurify": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"domutils": {
|
"domutils": {
|
||||||
"version": "1.7.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
|
||||||
@@ -6743,6 +6730,11 @@
|
|||||||
"websocket-driver": ">=0.5.1"
|
"websocket-driver": ">=0.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fflate": {
|
||||||
|
"version": "0.4.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
|
||||||
|
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
|
||||||
|
},
|
||||||
"figgy-pudding": {
|
"figgy-pudding": {
|
||||||
"version": "3.5.1",
|
"version": "3.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
|
||||||
@@ -7440,6 +7432,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"html2canvas": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-4+zqv87/a1LsaCrINV69wVLGG8GBZcYBboz1JPWEgiXcWoD9kroLzccsBRU/L9UlfV2MAZ+3J92U9IQPVMDeSQ==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"css-line-break": "2.0.1",
|
||||||
|
"text-segmentation": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"htmlparser2": {
|
"htmlparser2": {
|
||||||
"version": "3.10.1",
|
"version": "3.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
|
||||||
@@ -8369,6 +8371,42 @@
|
|||||||
"graceful-fs": "^4.1.6"
|
"graceful-fs": "^4.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jspdf": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-nsZ92YfbNG/EimR1yqmOkxf2D4iJRypBsw7pvP1aPiIEnoGITaLl6XDR/GYA36/R29vMZSBedpEhBCzutSGytA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.14.0",
|
||||||
|
"atob": "^2.1.2",
|
||||||
|
"btoa": "^1.2.1",
|
||||||
|
"canvg": "^3.0.6",
|
||||||
|
"core-js": "^3.6.0",
|
||||||
|
"dompurify": "^2.2.0",
|
||||||
|
"fflate": "^0.4.8",
|
||||||
|
"html2canvas": "^1.0.0-rc.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": {
|
||||||
|
"version": "7.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.0.tgz",
|
||||||
|
"integrity": "sha512-Nht8L0O8YCktmsDV6FqFue7vQLRx3Hb0B37lS5y0jDRqRxlBG4wIJHnf9/bgSE2UyipKFA01YtS+npRdTWBUyw==",
|
||||||
|
"requires": {
|
||||||
|
"regenerator-runtime": "^0.13.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"core-js": {
|
||||||
|
"version": "3.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.0.tgz",
|
||||||
|
"integrity": "sha512-L1TpFRWXZ76vH1yLM+z6KssLZrP8Z6GxxW4auoCj+XiViOzNPJCAuTIkn03BGdFe6Z5clX5t64wRIRypsZQrUg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"regenerator-runtime": {
|
||||||
|
"version": "0.13.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
||||||
|
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"jsprim": {
|
"jsprim": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||||
@@ -9658,8 +9696,7 @@
|
|||||||
"performance-now": {
|
"performance-now": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"picomatch": {
|
"picomatch": {
|
||||||
"version": "2.2.2",
|
"version": "2.2.2",
|
||||||
@@ -10546,6 +10583,15 @@
|
|||||||
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
|
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"raf": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"performance-now": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"randombytes": {
|
"randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
@@ -10923,6 +10969,12 @@
|
|||||||
"integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=",
|
"integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"rgbcolor": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-1lBezbMEplldom+ktDMHMGd1lF0=",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"rimraf": {
|
"rimraf": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||||
@@ -11648,6 +11700,12 @@
|
|||||||
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
|
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"stackblur-canvas": {
|
||||||
|
"version": "2.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz",
|
||||||
|
"integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"stackframe": {
|
"stackframe": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz",
|
||||||
@@ -11955,6 +12013,12 @@
|
|||||||
"has-flag": "^3.0.0"
|
"has-flag": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"svg-pathdata": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"svg-tags": {
|
"svg-tags": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
|
||||||
@@ -12041,6 +12105,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"text-segmentation": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-uTqvLxdBrVnx/CFQOtnf8tfzSXFm+1Qxau7Xi54j4OPTZokuDOX8qncQzrg2G8ZicAMOM8TgzFAYTb+AqNO4Cw==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"utrie": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"text-table": {
|
"text-table": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||||
@@ -12613,6 +12686,23 @@
|
|||||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
|
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"utrie": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-JPaDXF3vzgZxfeEwutdGzlrNoVFL5UvZcbO6Qo9D4GoahrieUPoMU8GCpVpR7MQqcKhmShIh8VlbEN3PLM3EBg==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"base64-arraybuffer": "^1.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"base64-arraybuffer": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA==",
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "3.3.3",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
|
||||||
@@ -12701,6 +12791,94 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vue-loader-v16": {
|
||||||
|
"version": "npm:vue-loader@16.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
|
||||||
|
"integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"hash-sum": "^2.0.0",
|
||||||
|
"loader-utils": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"emojis-list": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"json5": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"minimist": "^1.2.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"loader-utils": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"big.js": "^5.2.2",
|
||||||
|
"emojis-list": "^3.0.0",
|
||||||
|
"json5": "^2.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"vue-native-websocket": {
|
"vue-native-websocket": {
|
||||||
"version": "git+https://github.com/PhotonVision/vue-native-websocket.git#7a327918e03b215b6899b0d648c5130ece1fa912",
|
"version": "git+https://github.com/PhotonVision/vue-native-websocket.git#7a327918e03b215b6899b0d648c5130ece1fa912",
|
||||||
"from": "git+https://github.com/PhotonVision/vue-native-websocket.git#7a32791",
|
"from": "git+https://github.com/PhotonVision/vue-native-websocket.git#7a32791",
|
||||||
@@ -12749,7 +12927,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": {
|
"acorn": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
|
||||||
"integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo="
|
"integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13653,7 +13831,7 @@
|
|||||||
},
|
},
|
||||||
"browserify-aes": {
|
"browserify-aes": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||||
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
|
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"buffer-xor": "^1.0.3",
|
"buffer-xor": "^1.0.3",
|
||||||
@@ -13687,7 +13865,7 @@
|
|||||||
},
|
},
|
||||||
"browserify-rsa": {
|
"browserify-rsa": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
|
||||||
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
|
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "^4.1.0",
|
"bn.js": "^4.1.0",
|
||||||
@@ -13718,7 +13896,7 @@
|
|||||||
},
|
},
|
||||||
"buffer": {
|
"buffer": {
|
||||||
"version": "4.9.1",
|
"version": "4.9.1",
|
||||||
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
||||||
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
|
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"base64-js": "^1.0.2",
|
"base64-js": "^1.0.2",
|
||||||
@@ -13854,7 +14032,7 @@
|
|||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-styles": "^2.2.1",
|
"ansi-styles": "^2.2.1",
|
||||||
@@ -14101,7 +14279,7 @@
|
|||||||
},
|
},
|
||||||
"create-hash": {
|
"create-hash": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
||||||
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
|
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"cipher-base": "^1.0.1",
|
"cipher-base": "^1.0.1",
|
||||||
@@ -14113,7 +14291,7 @@
|
|||||||
},
|
},
|
||||||
"create-hmac": {
|
"create-hmac": {
|
||||||
"version": "1.1.7",
|
"version": "1.1.7",
|
||||||
"resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
|
||||||
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
|
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"cipher-base": "^1.0.3",
|
"cipher-base": "^1.0.3",
|
||||||
@@ -14320,7 +14498,7 @@
|
|||||||
},
|
},
|
||||||
"diffie-hellman": {
|
"diffie-hellman": {
|
||||||
"version": "5.0.3",
|
"version": "5.0.3",
|
||||||
"resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
|
||||||
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
|
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "^4.1.0",
|
"bn.js": "^4.1.0",
|
||||||
@@ -14396,7 +14574,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
||||||
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "0.7.2"
|
"ms": "0.7.2"
|
||||||
@@ -14435,7 +14613,7 @@
|
|||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
||||||
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "0.7.2"
|
"ms": "0.7.2"
|
||||||
@@ -15886,7 +16064,7 @@
|
|||||||
},
|
},
|
||||||
"http-errors": {
|
"http-errors": {
|
||||||
"version": "1.6.3",
|
"version": "1.6.3",
|
||||||
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||||
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
|
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"depd": "~1.1.2",
|
"depd": "~1.1.2",
|
||||||
@@ -16372,7 +16550,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "3.10.1",
|
"version": "3.10.1",
|
||||||
"resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
|
||||||
"integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
|
"integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16408,7 +16586,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16617,7 +16795,7 @@
|
|||||||
},
|
},
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "1.0.34",
|
"version": "1.0.34",
|
||||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
|
||||||
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
|
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-util-is": "~1.0.0",
|
"core-util-is": "~1.0.0",
|
||||||
@@ -16776,7 +16954,7 @@
|
|||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||||
},
|
},
|
||||||
"path-exists": {
|
"path-exists": {
|
||||||
@@ -16903,7 +17081,7 @@
|
|||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||||
},
|
},
|
||||||
"mixin-deep": {
|
"mixin-deep": {
|
||||||
@@ -16927,7 +17105,7 @@
|
|||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
@@ -16954,7 +17132,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.9.0",
|
"version": "2.9.0",
|
||||||
"resolved": "http://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
|
||||||
"integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
|
"integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"graceful-readlink": ">= 1.0.0"
|
"graceful-readlink": ">= 1.0.0"
|
||||||
@@ -17241,7 +17419,7 @@
|
|||||||
},
|
},
|
||||||
"onetime": {
|
"onetime": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
|
||||||
"integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k="
|
"integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k="
|
||||||
},
|
},
|
||||||
"optimist": {
|
"optimist": {
|
||||||
@@ -17346,7 +17524,7 @@
|
|||||||
},
|
},
|
||||||
"parse-asn1": {
|
"parse-asn1": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
|
||||||
"integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
|
"integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"asn1.js": "^4.0.0",
|
"asn1.js": "^4.0.0",
|
||||||
@@ -17569,7 +17747,7 @@
|
|||||||
},
|
},
|
||||||
"public-encrypt": {
|
"public-encrypt": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "http://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz",
|
||||||
"integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==",
|
"integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "^4.1.0",
|
"bn.js": "^4.1.0",
|
||||||
@@ -17685,7 +17863,7 @@
|
|||||||
},
|
},
|
||||||
"readable-stream": {
|
"readable-stream": {
|
||||||
"version": "2.3.6",
|
"version": "2.3.6",
|
||||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-util-is": "~1.0.0",
|
"core-util-is": "~1.0.0",
|
||||||
@@ -17998,7 +18176,7 @@
|
|||||||
},
|
},
|
||||||
"sha.js": {
|
"sha.js": {
|
||||||
"version": "2.4.11",
|
"version": "2.4.11",
|
||||||
"resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||||
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"inherits": "^2.0.1",
|
"inherits": "^2.0.1",
|
||||||
@@ -18176,7 +18354,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
||||||
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "0.7.2"
|
"ms": "0.7.2"
|
||||||
@@ -18205,7 +18383,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
||||||
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "0.7.2"
|
"ms": "0.7.2"
|
||||||
@@ -18243,7 +18421,7 @@
|
|||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "http://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
|
||||||
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "0.7.2"
|
"ms": "0.7.2"
|
||||||
@@ -18269,7 +18447,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
|
||||||
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
|
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "0.7.1"
|
"ms": "0.7.1"
|
||||||
@@ -18464,7 +18642,7 @@
|
|||||||
},
|
},
|
||||||
"table": {
|
"table": {
|
||||||
"version": "3.8.3",
|
"version": "3.8.3",
|
||||||
"resolved": "http://registry.npmjs.org/table/-/table-3.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
|
||||||
"integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
|
"integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "^4.7.0",
|
"ajv": "^4.7.0",
|
||||||
@@ -18521,7 +18699,7 @@
|
|||||||
},
|
},
|
||||||
"through": {
|
"through": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
|
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
|
||||||
},
|
},
|
||||||
"time-stamp": {
|
"time-stamp": {
|
||||||
@@ -18697,7 +18875,7 @@
|
|||||||
},
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "3.10.0",
|
"version": "3.10.0",
|
||||||
"resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
||||||
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
|
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"camelcase": "^1.0.2",
|
"camelcase": "^1.0.2",
|
||||||
@@ -19339,7 +19517,7 @@
|
|||||||
},
|
},
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||||
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"string-width": "^1.0.1",
|
"string-width": "^1.0.1",
|
||||||
@@ -20250,9 +20428,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"y18n": {
|
"y18n": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"axios": "^0.19.2",
|
"axios": "^0.19.2",
|
||||||
"core-js": "^2.6.11",
|
"core-js": "^2.6.11",
|
||||||
"downloadjs": "^1.4.7",
|
"downloadjs": "^1.4.7",
|
||||||
|
"jspdf": "^2.4.0",
|
||||||
"material-design-icons-iconfont": "^5.0.1",
|
"material-design-icons-iconfont": "^5.0.1",
|
||||||
"msgpack5": "^4.2.1",
|
"msgpack5": "^4.2.1",
|
||||||
"vue": "^2.6.12",
|
"vue": "^2.6.12",
|
||||||
|
|||||||
@@ -87,29 +87,79 @@
|
|||||||
</v-icon>
|
</v-icon>
|
||||||
</v-list-item-icon>
|
</v-list-item-icon>
|
||||||
<v-list-item-content>
|
<v-list-item-content>
|
||||||
<v-list-item-title>Advanced Mode</v-list-item-title>
|
<v-list-item-title>Compact Mode</v-list-item-title>
|
||||||
</v-list-item-content>
|
</v-list-item-content>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-list-item style="position: absolute; bottom: 0; left: 0;">
|
<div style="position: absolute; bottom: 0; left: 0;">
|
||||||
<v-list-item-icon>
|
<v-list-item>
|
||||||
<v-icon v-if="$store.state.backendConnected">
|
<v-list-item-icon>
|
||||||
mdi-wifi
|
<v-icon v-if="$store.state.settings.networkSettings.runNTServer">
|
||||||
</v-icon>
|
mdi-server
|
||||||
<v-icon
|
</v-icon>
|
||||||
v-else
|
<img
|
||||||
class="pulse"
|
v-else-if="$store.state.ntConnectionInfo.connected"
|
||||||
style="border-radius: 100%;"
|
src="@/assets/robot.svg"
|
||||||
>
|
alt=""
|
||||||
mdi-wifi-off
|
>
|
||||||
</v-icon>
|
<img
|
||||||
</v-list-item-icon>
|
v-else
|
||||||
<v-list-item-content>
|
class="pulse"
|
||||||
<v-list-item-title>
|
style="border-radius: 100%"
|
||||||
{{ $store.state.backendConnected ? "Connected" : "Trying to connect..." }}
|
src="@/assets/robot-off.svg"
|
||||||
</v-list-item-title>
|
alt=""
|
||||||
</v-list-item-content>
|
>
|
||||||
</v-list-item>
|
</v-list-item-icon>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title
|
||||||
|
v-if="$store.state.settings.networkSettings.runNTServer"
|
||||||
|
class="text-wrap"
|
||||||
|
>
|
||||||
|
NetworkTables server running for {{ $store.state.ntConnectionInfo.clients ? $store.state.ntConnectionInfo.clients : 'zero' }} clients!
|
||||||
|
</v-list-item-title>
|
||||||
|
<v-list-item-title
|
||||||
|
v-else-if="$store.state.ntConnectionInfo.connected && $store.state.backendConnected"
|
||||||
|
class="text-wrap"
|
||||||
|
>
|
||||||
|
Robot connected! {{ $store.state.ntConnectionInfo.address }}
|
||||||
|
</v-list-item-title>
|
||||||
|
<v-list-item-title
|
||||||
|
v-else
|
||||||
|
class="text-wrap"
|
||||||
|
>
|
||||||
|
Not connected to robot!
|
||||||
|
</v-list-item-title>
|
||||||
|
<router-link
|
||||||
|
v-if="!$store.state.settings.networkSettings.runNTServer"
|
||||||
|
to="settings"
|
||||||
|
class="accent--text"
|
||||||
|
@click="switchToSettingsTab"
|
||||||
|
>
|
||||||
|
Team number is {{ $store.state.settings.networkSettings.teamNumber }}
|
||||||
|
</router-link>
|
||||||
|
</v-list-item-content>
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item>
|
||||||
|
<v-list-item-icon>
|
||||||
|
<v-icon v-if="$store.state.backendConnected">
|
||||||
|
mdi-wifi
|
||||||
|
</v-icon>
|
||||||
|
<v-icon
|
||||||
|
v-else
|
||||||
|
class="pulse"
|
||||||
|
style="border-radius: 100%;"
|
||||||
|
>
|
||||||
|
mdi-wifi-off
|
||||||
|
</v-icon>
|
||||||
|
</v-list-item-icon>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title class="text-wrap">
|
||||||
|
{{ $store.state.backendConnected ? "Backend Connected" : "Trying to connect..." }}
|
||||||
|
</v-list-item-title>
|
||||||
|
</v-list-item-content>
|
||||||
|
</v-list-item>
|
||||||
|
</div>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
<v-main>
|
<v-main>
|
||||||
@@ -132,13 +182,39 @@
|
|||||||
>
|
>
|
||||||
<logs />
|
<logs />
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
<v-dialog
|
||||||
|
v-model="needsTeamNumberSet"
|
||||||
|
width="500"
|
||||||
|
dark
|
||||||
|
persistent
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
dark
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
>
|
||||||
|
<v-card-title>No team number set!</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
PhotonVision cannot connect to your robot! Please
|
||||||
|
<router-link
|
||||||
|
to="settings"
|
||||||
|
class="accent--text"
|
||||||
|
@click="switchToSettingsTab"
|
||||||
|
>
|
||||||
|
vist the settings tab
|
||||||
|
</router-link>
|
||||||
|
and set your team number.
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
</v-app>
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Logs from "./views/LogsView"
|
import Logs from "./views/LogsView"
|
||||||
|
// import {mapState} from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
Logs
|
Logs
|
||||||
@@ -147,8 +223,16 @@ import Logs from "./views/LogsView"
|
|||||||
// Used so that we can switch back to the previously selected pipeline after camera calibration
|
// Used so that we can switch back to the previously selected pipeline after camera calibration
|
||||||
previouslySelectedIndices: [],
|
previouslySelectedIndices: [],
|
||||||
timer: undefined,
|
timer: undefined,
|
||||||
|
teamNumberDialog: true
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
|
needsTeamNumberSet: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.settings.networkSettings.teamNumber < 1
|
||||||
|
&& this.teamNumberDialog && this.$store.state.backendConnected
|
||||||
|
&& !this.$route.name.toLowerCase().includes("settings");
|
||||||
|
}
|
||||||
|
},
|
||||||
compact: {
|
compact: {
|
||||||
get() {
|
get() {
|
||||||
if (this.$store.state.compactMode === undefined) {
|
if (this.$store.state.compactMode === undefined) {
|
||||||
@@ -197,12 +281,12 @@ import Logs from "./views/LogsView"
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.$options.sockets.onopen = () => {
|
this.$options.sockets.onopen = () => {
|
||||||
this.$store.state.backendConnected = true;
|
this.$store.commit("backendConnected", true)
|
||||||
this.$store.state.connectedCallbacks.forEach(it => it())
|
this.$store.state.connectedCallbacks.forEach(it => it())
|
||||||
};
|
};
|
||||||
|
|
||||||
let closed = () => {
|
let closed = () => {
|
||||||
this.$store.state.backendConnected = false;
|
this.$store.commit("backendConnected", false)
|
||||||
};
|
};
|
||||||
this.$options.sockets.onclose = closed;
|
this.$options.sockets.onclose = closed;
|
||||||
this.$options.sockets.onerror = closed;
|
this.$options.sockets.onerror = closed;
|
||||||
@@ -213,6 +297,8 @@ import Logs from "./views/LogsView"
|
|||||||
handleMessage(key, value) {
|
handleMessage(key, value) {
|
||||||
if (key === "logMessage") {
|
if (key === "logMessage") {
|
||||||
this.logMessage(value["logMessage"], value["logLevel"]);
|
this.logMessage(value["logMessage"], value["logLevel"]);
|
||||||
|
} else if(key === "log"){
|
||||||
|
this.logMessage(value["logMessage"]["logMessage"], value["logMessage"]["logLevel"]);
|
||||||
} else if (key === "updatePipelineResult") {
|
} else if (key === "updatePipelineResult") {
|
||||||
this.$store.commit('mutatePipelineResults', value)
|
this.$store.commit('mutatePipelineResults', value)
|
||||||
} else if (this.$store.state.hasOwnProperty(key)) {
|
} else if (this.$store.state.hasOwnProperty(key)) {
|
||||||
@@ -255,8 +341,7 @@ import Logs from "./views/LogsView"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.previouslySelectedIndices = null;
|
this.previouslySelectedIndices = null;
|
||||||
}
|
},
|
||||||
,
|
|
||||||
switchToSettingsTab() {
|
switchToSettingsTab() {
|
||||||
this.axios.post('http://' + this.$address + '/api/sendMetrics', {})
|
this.axios.post('http://' + this.$address + '/api/sendMetrics', {})
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
photon-client/src/assets/logoMono.png
Normal file
BIN
photon-client/src/assets/logoMono.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
1
photon-client/src/assets/robot-off.svg
Normal file
1
photon-client/src/assets/robot-off.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path fill="white" d="M23 15V18C23 18.5 22.64 18.88 22.17 18.97L18.97 15.77C19 15.68 19 15.59 19 15.5C19 14.12 17.88 13 16.5 13C16.41 13 16.32 13 16.23 13.03L10.2 7H11V5.73C10.4 5.39 10 4.74 10 4C10 2.9 10.9 2 12 2S14 2.9 14 4C14 4.74 13.6 5.39 13 5.73V7H14C17.87 7 21 10.13 21 14H22C22.55 14 23 14.45 23 15M22.11 21.46L20.84 22.73L19.89 21.78C19.62 21.92 19.32 22 19 22H5C3.9 22 3 21.11 3 20V19H2C1.45 19 1 18.55 1 18V15C1 14.45 1.45 14 2 14H3C3 11.53 4.29 9.36 6.22 8.11L1.11 3L2.39 1.73L22.11 21.46M10 15.5C10 14.12 8.88 13 7.5 13S5 14.12 5 15.5 6.12 18 7.5 18 10 16.88 10 15.5M16.07 17.96L14.04 15.93C14.23 16.97 15.04 17.77 16.07 17.96Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 928 B |
1
photon-client/src/assets/robot.svg
Normal file
1
photon-client/src/assets/robot.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path fill="white" d="M12,2C13.1,2 14,2.9 14,4C14,4.74 13.6,5.39 13,5.73V7H14C17.87,7 21,10.13 21,14H22C22.55,14 23,14.45 23,15V18C23,18.55 22.55,19 22,19H21V20C21,21.1 20.1,22 19,22H5C3.9,22 3,21.1 3,20V19H2C1.45,19 1,18.55 1,18V15C1,14.45 1.45,14 2,14H3C3,10.13 6.13,7 10,7H11V5.73C10.4,5.39 10,4.74 10,4C10,2.9 10.9,2 12,2M7.5,13C6.12,13 5,14.12 5,15.5C5,16.88 6.12,18 7.5,18C8.88,18 10,16.88 10,15.5C10,14.12 8.88,13 7.5,13M16.5,13C15.12,13 14,14.12 14,15.5C14,16.88 15.12,18 16.5,18C17.88,18 19,16.88 19,15.5C19,14.12 17.88,13 16.5,13Z" /></svg>
|
||||||
|
After Width: | Height: | Size: 827 B |
@@ -13,7 +13,7 @@
|
|||||||
export default {
|
export default {
|
||||||
name: "CvImage",
|
name: "CvImage",
|
||||||
// eslint-disable-next-line vue/require-prop-types
|
// eslint-disable-next-line vue/require-prop-types
|
||||||
props: ['address', 'scale', 'maxHeight', 'maxHeightMd', 'maxHeightXl', 'colorPicking', 'id', 'disconnected'],
|
props: ['address', 'scale', 'maxHeight', 'maxHeightMd', 'maxHeightLg', 'maxHeightXl', 'colorPicking', 'id', 'disconnected'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
seed: 1.0,
|
seed: 1.0,
|
||||||
@@ -37,7 +37,9 @@
|
|||||||
|
|
||||||
if (this.$vuetify.breakpoint.xl) {
|
if (this.$vuetify.breakpoint.xl) {
|
||||||
ret["max-height"] = this.maxHeightXl;
|
ret["max-height"] = this.maxHeightXl;
|
||||||
} else if (this.$vuetify.breakpoint.mdAndUp) {
|
} else if (this.$vuetify.breakpoint.lg) {
|
||||||
|
ret["max-height"] = this.maxHeightLg;
|
||||||
|
} else if (this.$vuetify.breakpoint.md) {
|
||||||
ret["max-height"] = this.maxHeightMd;
|
ret["max-height"] = this.maxHeightMd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<v-radio-group
|
<v-row
|
||||||
v-model="localValue"
|
dense
|
||||||
row
|
align="center"
|
||||||
dark
|
|
||||||
:mandatory="true"
|
|
||||||
>
|
>
|
||||||
<v-radio
|
<v-col :cols="12 - (inputCols || 8)">
|
||||||
v-for="(name,index) in list"
|
<tooltipped-label
|
||||||
:key="index"
|
:tooltip="tooltip"
|
||||||
color="#ffd843"
|
:text="name"
|
||||||
:label="name"
|
/>
|
||||||
:value="index"
|
</v-col>
|
||||||
:disabled="disabled"
|
<v-col :cols="inputCols || 8">
|
||||||
/>
|
<v-radio-group
|
||||||
</v-radio-group>
|
v-model="localValue"
|
||||||
|
row
|
||||||
|
dark
|
||||||
|
:mandatory="true"
|
||||||
|
>
|
||||||
|
<v-radio
|
||||||
|
v-for="(radioName,index) in list"
|
||||||
|
:key="index"
|
||||||
|
color="#ffd843"
|
||||||
|
:label="radioName"
|
||||||
|
:value="index"
|
||||||
|
:disabled="disabled"
|
||||||
|
/>
|
||||||
|
</v-radio-group>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import TooltippedLabel from "./cv-tooltipped-label";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Radio',
|
name: 'Radio',
|
||||||
|
components: {
|
||||||
|
TooltippedLabel
|
||||||
|
},
|
||||||
// eslint-disable-next-line vue/require-prop-types
|
// eslint-disable-next-line vue/require-prop-types
|
||||||
props: ['value', 'list', 'disabled'],
|
props: ['name', 'value', 'list', 'disabled', 'inputCols', 'tooltip'],
|
||||||
data() {
|
data() {
|
||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,10 +15,13 @@
|
|||||||
:value="localValue"
|
:value="localValue"
|
||||||
:max="max"
|
:max="max"
|
||||||
:min="min"
|
:min="min"
|
||||||
|
:disabled="disabled"
|
||||||
hide-details
|
hide-details
|
||||||
class="align-center"
|
class="align-center"
|
||||||
dark
|
dark
|
||||||
color="accent"
|
:color="inverted ? 'rgba(255, 255, 255, 0.2)' : 'accent'"
|
||||||
|
:track-color="inverted ? 'accent' : undefined"
|
||||||
|
thumb-color="accent"
|
||||||
:step="step"
|
:step="step"
|
||||||
@input="handleInput"
|
@input="handleInput"
|
||||||
@mousedown="$emit('rollback', localValue)"
|
@mousedown="$emit('rollback', localValue)"
|
||||||
@@ -34,7 +37,7 @@
|
|||||||
hide-details
|
hide-details
|
||||||
single-line
|
single-line
|
||||||
type="number"
|
type="number"
|
||||||
style="width: 50px"
|
style="width: 60px"
|
||||||
:step="step"
|
:step="step"
|
||||||
@input="handleChange"
|
@input="handleChange"
|
||||||
@focus="prependFocused = true"
|
@focus="prependFocused = true"
|
||||||
@@ -53,7 +56,7 @@
|
|||||||
hide-details
|
hide-details
|
||||||
single-line
|
single-line
|
||||||
type="number"
|
type="number"
|
||||||
style="width: 50px"
|
style="width: 60px"
|
||||||
:step="step"
|
:step="step"
|
||||||
@input="handleChange"
|
@input="handleChange"
|
||||||
@focus="appendFocused = true"
|
@focus="appendFocused = true"
|
||||||
@@ -75,7 +78,7 @@ export default {
|
|||||||
TooltippedLabel,
|
TooltippedLabel,
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line vue/require-prop-types
|
// eslint-disable-next-line vue/require-prop-types
|
||||||
props: ["name", "min", "max", "value", "step", "tooltip"],
|
props: ["name", "min", "max", "value", "step", "tooltip", "disabled", "inverted"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
prependFocused: false,
|
prependFocused: false,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<v-tooltip
|
<v-tooltip
|
||||||
:disabled="tooltip === undefined"
|
:disabled="tooltip === undefined"
|
||||||
right
|
right
|
||||||
open-delay="600"
|
open-delay="300"
|
||||||
>
|
>
|
||||||
<template v-slot:activator="{ on, attrs }">
|
<template v-slot:activator="{ on, attrs }">
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<v-row align="center">
|
<v-row
|
||||||
|
align="center"
|
||||||
|
class="pl-6"
|
||||||
|
>
|
||||||
<v-col
|
<v-col
|
||||||
cols="10"
|
cols="10"
|
||||||
md="5"
|
md="5"
|
||||||
lg="10"
|
lg="10"
|
||||||
class="pt-0 pb-0 pl-6"
|
no-gutters
|
||||||
|
class="pa-0"
|
||||||
>
|
>
|
||||||
<CVselect
|
<CVselect
|
||||||
v-if="isCameraNameEdit === false"
|
v-if="isCameraNameEdit === false"
|
||||||
@@ -59,7 +63,8 @@
|
|||||||
cols="10"
|
cols="10"
|
||||||
md="5"
|
md="5"
|
||||||
lg="10"
|
lg="10"
|
||||||
class="pt-0 pb-0 pl-6"
|
no-gutters
|
||||||
|
class="pa-0"
|
||||||
>
|
>
|
||||||
<CVselect
|
<CVselect
|
||||||
v-model="currentPipelineIndex"
|
v-model="currentPipelineIndex"
|
||||||
@@ -88,7 +93,11 @@
|
|||||||
menu
|
menu
|
||||||
</v-icon>
|
</v-icon>
|
||||||
</template>
|
</template>
|
||||||
<v-list dense>
|
<v-list
|
||||||
|
dark
|
||||||
|
dense
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
<v-list-item @click="toPipelineNameChange">
|
<v-list-item @click="toPipelineNameChange">
|
||||||
<v-list-item-title>
|
<v-list-item-title>
|
||||||
<CVicon
|
<CVicon
|
||||||
@@ -119,7 +128,7 @@
|
|||||||
/>
|
/>
|
||||||
</v-list-item-title>
|
</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-list-item @click="openDuplicateDialog">
|
<v-list-item @click="duplicatePipeline">
|
||||||
<v-list-item-title>
|
<v-list-item-title>
|
||||||
<CVicon
|
<CVicon
|
||||||
color="#c5c5c5"
|
color="#c5c5c5"
|
||||||
@@ -132,66 +141,47 @@
|
|||||||
</v-list>
|
</v-list>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
<v-col
|
||||||
|
v-if="currentPipelineType >= 0"
|
||||||
|
cols="10"
|
||||||
|
md="11"
|
||||||
|
lg="10"
|
||||||
|
no-gutters
|
||||||
|
class="pa-0"
|
||||||
|
>
|
||||||
|
<CVselect
|
||||||
|
v-model="currentPipelineType"
|
||||||
|
name="Type"
|
||||||
|
tooltip="Changes the pipeline type, which changes the type of processing that will happen on input frames"
|
||||||
|
:list="['Reflective Tape', 'Colored Shape']"
|
||||||
|
@input="e => showTypeDialog(e)"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<!--pipeline duplicate dialog-->
|
|
||||||
<v-dialog
|
|
||||||
v-model="duplicateDialog"
|
|
||||||
dark
|
|
||||||
width="500"
|
|
||||||
height="357"
|
|
||||||
>
|
|
||||||
<v-card dark>
|
|
||||||
<v-card-title
|
|
||||||
class="headline"
|
|
||||||
primary-title
|
|
||||||
>
|
|
||||||
Duplicate Pipeline
|
|
||||||
</v-card-title>
|
|
||||||
<v-card-text>
|
|
||||||
<CVselect
|
|
||||||
v-model="pipeIndexToDuplicate"
|
|
||||||
name="Pipeline"
|
|
||||||
:list="$store.getters.pipelineList"
|
|
||||||
/>
|
|
||||||
</v-card-text>
|
|
||||||
<v-divider />
|
|
||||||
<v-card-actions>
|
|
||||||
<v-spacer />
|
|
||||||
<v-btn
|
|
||||||
color="#ffd843"
|
|
||||||
@click="duplicatePipeline"
|
|
||||||
>
|
|
||||||
Duplicate
|
|
||||||
</v-btn>
|
|
||||||
<v-btn
|
|
||||||
color="error"
|
|
||||||
@click="closeDuplicateDialog"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</v-btn>
|
|
||||||
</v-card-actions>
|
|
||||||
</v-card>
|
|
||||||
</v-dialog>
|
|
||||||
<!--pipeline naming dialog-->
|
<!--pipeline naming dialog-->
|
||||||
<v-dialog
|
<v-dialog
|
||||||
v-model="namingDialog"
|
v-model="namingDialog"
|
||||||
dark
|
dark
|
||||||
|
persistent
|
||||||
width="500"
|
width="500"
|
||||||
height="357"
|
height="357"
|
||||||
>
|
>
|
||||||
<v-card dark>
|
<v-card
|
||||||
|
dark
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
<v-card-title
|
<v-card-title
|
||||||
class="headline"
|
class="headline"
|
||||||
primary-title
|
primary-title
|
||||||
>
|
>
|
||||||
Pipeline Name
|
{{ isPipelineNameEdit ? "Edit Pipeline Name" : "Create Pipeline" }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<CVinput
|
<CVinput
|
||||||
v-model="newPipelineName"
|
v-model="newPipelineName"
|
||||||
name="Pipeline"
|
name="Name"
|
||||||
:error-message="checkPipelineName"
|
:error-message="checkPipelineName"
|
||||||
@Enter="savePipelineNameChange"
|
|
||||||
/>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-divider />
|
<v-divider />
|
||||||
@@ -213,161 +203,204 @@
|
|||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
<v-dialog
|
||||||
|
v-model="showPipeTypeDialog"
|
||||||
|
width="600"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
color="primary"
|
||||||
|
dark
|
||||||
|
>
|
||||||
|
<v-card-title>Change Pipeline Type</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
Changing the type of this pipeline will erase the current pipeline's settings and replace it with a new {{ ['Reflective', 'Shape'][proposedPipelineType] }} pipeline. <b class="red--text format_bold">You will lose all settings for the pipeline
|
||||||
|
"{{ ($store.getters.isDriverMode ? ['Driver Mode'] : []).concat($store.getters.pipelineList)[currentPipelineIndex] }}."</b> Are you sure you want to do this?
|
||||||
|
<v-row
|
||||||
|
class="mt-6"
|
||||||
|
style="display: flex; align-items: center; justify-content: center"
|
||||||
|
align="center"
|
||||||
|
>
|
||||||
|
<v-btn
|
||||||
|
class="mr-3"
|
||||||
|
color="red"
|
||||||
|
width="250"
|
||||||
|
@click="e => changePipeType(true)"
|
||||||
|
>
|
||||||
|
Yes, replace this pipeline
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
class="ml-10"
|
||||||
|
color="secondary"
|
||||||
|
width="250"
|
||||||
|
@click="e => changePipeType(false)"
|
||||||
|
>
|
||||||
|
No, take me back
|
||||||
|
</v-btn>
|
||||||
|
</v-row>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CVicon from '../common/cv-icon'
|
import CVicon from '../common/cv-icon'
|
||||||
import CVselect from '../common/cv-select'
|
import CVselect from '../common/cv-select'
|
||||||
import CVinput from '../common/cv-input'
|
import CVinput from '../common/cv-input'
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "CameraAndPipelineSelect",
|
|
||||||
components: {
|
|
||||||
CVicon,
|
|
||||||
CVselect,
|
|
||||||
CVinput
|
|
||||||
},
|
|
||||||
data: () => {
|
|
||||||
return {
|
|
||||||
re: RegExp("^[A-Za-z0-9 \\-)(]*[A-Za-z0-9][A-Za-z0-9 \\-)(.]*$"),
|
|
||||||
isCameraNameEdit: false,
|
|
||||||
newCameraName: "",
|
|
||||||
cameraNameError: "",
|
|
||||||
isPipelineNameEdit: false,
|
|
||||||
namingDialog: false,
|
|
||||||
newPipelineName: "",
|
|
||||||
duplicateDialog: false,
|
|
||||||
pipeIndexToDuplicate: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
checkCameraName() {
|
|
||||||
if (this.newCameraName !== this.$store.getters.cameraList[this.currentCameraIndex]) {
|
|
||||||
if (this.re.test(this.newCameraName)) {
|
|
||||||
for (let cam in this.cameraList) {
|
|
||||||
if (this.cameraList.hasOwnProperty(cam)) {
|
|
||||||
if (this.newCameraName === this.cameraList[cam]) {
|
|
||||||
return "A camera by that name already Exists"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return "A camera name can only contain letters, numbers and spaces"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
checkPipelineName() {
|
|
||||||
if (this.newPipelineName !== this.$store.getters.pipelineList[this.currentPipelineIndex - 1] || this.isPipelineNameEdit === false) {
|
|
||||||
if (this.re.test(this.newPipelineName)) {
|
|
||||||
for (let pipe in this.$store.getters.pipelineList) {
|
|
||||||
if (this.$store.getters.pipelineList.hasOwnProperty(pipe)) {
|
|
||||||
if (this.newPipelineName === this.$store.getters.pipelineList[pipe]) {
|
|
||||||
return "A pipeline with this name already exists"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return "A pipeline name can only contain letters, numbers, and spaces"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
},
|
|
||||||
currentCameraIndex: {
|
|
||||||
get() {
|
|
||||||
return this.$store.getters.currentCameraIndex;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.$store.commit('currentCameraIndex', value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
currentPipelineIndex: {
|
|
||||||
get() {
|
|
||||||
return this.$store.getters.currentPipelineIndex + (this.$store.getters.isDriverMode ? 1 : 0);
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.$store.commit('currentPipelineIndex', value - (this.$store.getters.isDriverMode ? 1 : 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changeCameraName() {
|
|
||||||
this.newCameraName = this.$store.getters.cameraList[this.currentCameraIndex];
|
|
||||||
this.isCameraNameEdit = true;
|
|
||||||
},
|
|
||||||
saveCameraNameChange() {
|
|
||||||
if (this.checkCameraName === "") {
|
|
||||||
// this.handleInputWithIndex("changeCameraName", this.newCameraName);
|
|
||||||
this.axios.post('http://' + this.$address + '/api/setCameraNickname',
|
|
||||||
{name: this.newCameraName, cameraIndex: this.$store.getters.currentCameraIndex})
|
|
||||||
// eslint-disable-next-line
|
|
||||||
.then(r => {
|
|
||||||
this.$emit('camera-name-changed')
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
console.log("HTTP error while changing camera name " + e);
|
|
||||||
this.$emit('camera-name-changed')
|
|
||||||
})
|
|
||||||
this.discardCameraNameChange();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
discardCameraNameChange() {
|
|
||||||
this.isCameraNameEdit = false;
|
|
||||||
this.newCameraName = "";
|
|
||||||
},
|
|
||||||
toPipelineNameChange() {
|
|
||||||
this.newPipelineName = this.$store.getters.pipelineList[this.currentPipelineIndex - 1];
|
|
||||||
this.isPipelineNameEdit = true;
|
|
||||||
this.namingDialog = true;
|
|
||||||
},
|
|
||||||
toCreatePipeline() {
|
|
||||||
this.newPipelineName = "New Pipeline";
|
|
||||||
this.isPipelineNameEdit = false;
|
|
||||||
this.namingDialog = true;
|
|
||||||
},
|
|
||||||
openDuplicateDialog() {
|
|
||||||
this.pipeIndexToDuplicate = this.currentPipelineIndex - 1;
|
|
||||||
this.duplicateDialog = true;
|
|
||||||
},
|
|
||||||
deleteCurrentPipeline() {
|
|
||||||
if (this.$store.getters.pipelineList.length > 1) {
|
|
||||||
this.handleInputWithIndex('deleteCurrentPipeline', {});
|
|
||||||
} else {
|
|
||||||
this.snackbar = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
savePipelineNameChange() {
|
|
||||||
if (this.checkPipelineName === "") {
|
|
||||||
if (this.isPipelineNameEdit) {
|
|
||||||
this.handleInputWithIndex("changePipelineName", this.newPipelineName);
|
|
||||||
} else {
|
|
||||||
this.handleInputWithIndex("addNewPipeline", this.newPipelineName);
|
|
||||||
}
|
|
||||||
this.discardPipelineNameChange();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
duplicatePipeline() {
|
|
||||||
// if (!this.anotherCamera) {
|
|
||||||
// this.pipelineDuplicate.camera = -1
|
|
||||||
// }
|
|
||||||
this.handleInputWithIndex("duplicatePipeline", this.pipeIndexToDuplicate);
|
|
||||||
// this.axios.post("http://" + this.$address + "/api/vision/duplicate", this.pipeIndexToDuplicate);
|
|
||||||
|
|
||||||
this.closeDuplicateDialog();
|
|
||||||
},
|
|
||||||
closeDuplicateDialog() {
|
|
||||||
this.duplicateDialog = false;
|
|
||||||
this.pipeIndexToDuplicate = undefined;
|
|
||||||
},
|
|
||||||
discardPipelineNameChange() {
|
|
||||||
this.namingDialog = false;
|
|
||||||
this.isPipelineNameEdit = false;
|
|
||||||
this.newPipelineName = "";
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "CameraAndPipelineSelect",
|
||||||
|
components: {
|
||||||
|
CVicon,
|
||||||
|
CVselect,
|
||||||
|
CVinput
|
||||||
|
},
|
||||||
|
data: () => {
|
||||||
|
return {
|
||||||
|
re: RegExp("^[A-Za-z0-9 \\-)(]*[A-Za-z0-9][A-Za-z0-9 \\-)(.]*$"),
|
||||||
|
isCameraNameEdit: false,
|
||||||
|
newCameraName: "",
|
||||||
|
cameraNameError: "",
|
||||||
|
isPipelineNameEdit: false,
|
||||||
|
namingDialog: false,
|
||||||
|
newPipelineName: "",
|
||||||
|
duplicateDialog: false,
|
||||||
|
showPipeTypeDialog: false,
|
||||||
|
proposedPipelineType : 0,
|
||||||
|
pipeIndexToDuplicate: undefined
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
checkCameraName() {
|
||||||
|
if (this.newCameraName !== this.$store.getters.cameraList[this.currentCameraIndex]) {
|
||||||
|
if (this.re.test(this.newCameraName)) {
|
||||||
|
for (let cam in this.cameraList) {
|
||||||
|
if (this.cameraList.hasOwnProperty(cam)) {
|
||||||
|
if (this.newCameraName === this.cameraList[cam]) {
|
||||||
|
return "A camera by that name already exists"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "A camera name can only contain letters, numbers, and spaces"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
checkPipelineName() {
|
||||||
|
if (this.newPipelineName !== this.$store.getters.pipelineList[this.currentPipelineIndex - 1] || this.isPipelineNameEdit === false) {
|
||||||
|
if (this.re.test(this.newPipelineName)) {
|
||||||
|
for (let pipe in this.$store.getters.pipelineList) {
|
||||||
|
if (this.$store.getters.pipelineList.hasOwnProperty(pipe)) {
|
||||||
|
if (this.newPipelineName === this.$store.getters.pipelineList[pipe]) {
|
||||||
|
return "A pipeline with this name already exists"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "A pipeline name can only contain letters, numbers, and spaces"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
currentCameraIndex: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentCameraIndex;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$store.commit('currentCameraIndex', value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentPipelineIndex: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineIndex + (this.$store.getters.isDriverMode ? 1 : 0);
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$store.commit('currentPipelineIndex', value - (this.$store.getters.isDriverMode ? 1 : 0));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentPipelineType: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.pipelineType - 2;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
value; // nop, since we have the dialog for this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showTypeDialog(idx) {
|
||||||
|
// Only show the dialog if it's a new type
|
||||||
|
this.showPipeTypeDialog = idx !== this.currentPipelineType;
|
||||||
|
this.proposedPipelineType = idx;
|
||||||
|
},
|
||||||
|
changePipeType(actuallyChange) {
|
||||||
|
const newIdx = actuallyChange ? this.proposedPipelineType : this.currentPipelineType
|
||||||
|
this.handleInputWithIndex('pipelineType', newIdx);
|
||||||
|
this.showPipeTypeDialog = false;
|
||||||
|
},
|
||||||
|
changeCameraName() {
|
||||||
|
this.newCameraName = this.$store.getters.cameraList[this.currentCameraIndex];
|
||||||
|
this.isCameraNameEdit = true;
|
||||||
|
},
|
||||||
|
saveCameraNameChange() {
|
||||||
|
if (this.checkCameraName === "") {
|
||||||
|
// this.handleInputWithIndex("changeCameraName", this.newCameraName);
|
||||||
|
this.axios.post('http://' + this.$address + '/api/setCameraNickname',
|
||||||
|
{name: this.newCameraName, cameraIndex: this.$store.getters.currentCameraIndex})
|
||||||
|
// eslint-disable-next-line
|
||||||
|
.then(r => {
|
||||||
|
this.$emit('camera-name-changed')
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log("HTTP error while changing camera name " + e);
|
||||||
|
this.$emit('camera-name-changed')
|
||||||
|
})
|
||||||
|
this.discardCameraNameChange();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
discardCameraNameChange() {
|
||||||
|
this.isCameraNameEdit = false;
|
||||||
|
this.newCameraName = "";
|
||||||
|
},
|
||||||
|
toPipelineNameChange() {
|
||||||
|
this.newPipelineName = this.$store.getters.pipelineList[this.currentPipelineIndex - 1];
|
||||||
|
this.isPipelineNameEdit = true;
|
||||||
|
this.namingDialog = true;
|
||||||
|
},
|
||||||
|
toCreatePipeline() {
|
||||||
|
this.newPipelineName = "New Pipeline";
|
||||||
|
this.isPipelineNameEdit = false;
|
||||||
|
this.namingDialog = true;
|
||||||
|
},
|
||||||
|
deleteCurrentPipeline() {
|
||||||
|
if (this.$store.getters.pipelineList.length > 1) {
|
||||||
|
this.handleInputWithIndex('deleteCurrentPipeline', {});
|
||||||
|
} else {
|
||||||
|
this.snackbar = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
savePipelineNameChange() {
|
||||||
|
if (this.checkPipelineName === "") {
|
||||||
|
if (this.isPipelineNameEdit) {
|
||||||
|
this.handleInputWithIndex("changePipelineName", this.newPipelineName);
|
||||||
|
} else {
|
||||||
|
this.handleInputWithIndex("addNewPipeline", [this.newPipelineName, this.currentPipelineType]); // 0 for reflective, 1 for colored shpae
|
||||||
|
}
|
||||||
|
this.discardPipelineNameChange();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
duplicatePipeline() {
|
||||||
|
this.handleInputWithIndex("duplicatePipeline", this.currentPipelineIndex);
|
||||||
|
},
|
||||||
|
discardPipelineNameChange() {
|
||||||
|
this.namingDialog = false;
|
||||||
|
this.isPipelineNameEdit = false;
|
||||||
|
this.newPipelineName = "";
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
7
photon-client/src/jsPDFFonts/Prompt-Regular-normal.js
Normal file
7
photon-client/src/jsPDFFonts/Prompt-Regular-normal.js
Normal file
File diff suppressed because one or more lines are too long
7
photon-client/src/jsPDFFonts/readme.md
Normal file
7
photon-client/src/jsPDFFonts/readme.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# JSPDF Fonts
|
||||||
|
|
||||||
|
These are .js interpretations of the .tff files in the branding folder. They are used by jspdf to apply branding-approprate fonts to any .pdf file generation (ex: calibration targets)
|
||||||
|
|
||||||
|
https://peckconsulting.s3.amazonaws.com/fontconverter/fontconverter.html is the converter used to generate them.
|
||||||
|
|
||||||
|
https://www.devlinpeck.com/tutorials/jspdf-custom-font has more info creating/using them.
|
||||||
@@ -29,9 +29,11 @@ Vue.use(VueAxios, axios);
|
|||||||
Vue.prototype.$msgPack = msgPack(true);
|
Vue.prototype.$msgPack = msgPack(true);
|
||||||
|
|
||||||
import {dataHandleMixin} from './mixins/global/dataHandleMixin'
|
import {dataHandleMixin} from './mixins/global/dataHandleMixin'
|
||||||
|
|
||||||
Vue.mixin(dataHandleMixin);
|
Vue.mixin(dataHandleMixin);
|
||||||
|
|
||||||
|
import {stateMixin} from './mixins/global/stateMixin'
|
||||||
|
Vue.mixin(stateMixin);
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
router,
|
router,
|
||||||
store,
|
store,
|
||||||
|
|||||||
10
photon-client/src/mixins/global/stateMixin.js
Normal file
10
photon-client/src/mixins/global/stateMixin.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export const stateMixin = {
|
||||||
|
methods: {
|
||||||
|
currentPipelineType() {
|
||||||
|
return this.$store.getters.pipelineType
|
||||||
|
},
|
||||||
|
currentPipelineSettings() {
|
||||||
|
return this.$store.getters.currentPipelineSettings
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -6,8 +6,10 @@ function initColorPicker() {
|
|||||||
canvas = document.createElement('canvas');
|
canvas = document.createElement('canvas');
|
||||||
|
|
||||||
image = document.querySelector('#normal-stream');
|
image = document.querySelector('#normal-stream');
|
||||||
canvas.width = image.width;
|
if (image !== null) {
|
||||||
canvas.height = image.height;
|
canvas.width = image.width;
|
||||||
|
canvas.height = image.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Called on click of the image,
|
//Called on click of the image,
|
||||||
|
|||||||
@@ -15,6 +15,15 @@ export default new Vuex.Store({
|
|||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
backendConnected: false,
|
backendConnected: false,
|
||||||
|
ntConnectionInfo: {
|
||||||
|
connected: false,
|
||||||
|
address: "",
|
||||||
|
clients: 0,
|
||||||
|
},
|
||||||
|
networkInfo: {
|
||||||
|
possibleRios: ["Loading..."],
|
||||||
|
deviceips: ["Loading..."],
|
||||||
|
},
|
||||||
connectedCallbacks: [],
|
connectedCallbacks: [],
|
||||||
colorPicking: false,
|
colorPicking: false,
|
||||||
logsOverlay: false,
|
logsOverlay: false,
|
||||||
@@ -42,13 +51,14 @@ export default new Vuex.Store({
|
|||||||
isFovConfigurable: true,
|
isFovConfigurable: true,
|
||||||
calibrated: false,
|
calibrated: false,
|
||||||
currentPipelineSettings: {
|
currentPipelineSettings: {
|
||||||
pipelineType: 2, // One of "driver", "reflective", "shape"
|
pipelineType: 2, // One of "calib", "driver", "reflective", "shape"
|
||||||
// 2 is reflective
|
// 2 is reflective
|
||||||
|
|
||||||
// Settings that apply to all pipeline types
|
// Settings that apply to all pipeline types
|
||||||
cameraExposure: 1,
|
cameraExposure: 1,
|
||||||
cameraBrightness: 2,
|
cameraBrightness: 2,
|
||||||
cameraGain: 3,
|
cameraRedGain: 3,
|
||||||
|
cameraBlueGain: 4,
|
||||||
inputImageRotationMode: 0,
|
inputImageRotationMode: 0,
|
||||||
cameraVideoModeIndex: 0,
|
cameraVideoModeIndex: 0,
|
||||||
streamingFrameDivisor: 0,
|
streamingFrameDivisor: 0,
|
||||||
@@ -57,10 +67,13 @@ export default new Vuex.Store({
|
|||||||
hsvHue: [0, 15],
|
hsvHue: [0, 15],
|
||||||
hsvSaturation: [0, 15],
|
hsvSaturation: [0, 15],
|
||||||
hsvValue: [0, 25],
|
hsvValue: [0, 25],
|
||||||
|
hueInverted: false,
|
||||||
contourArea: [0, 12],
|
contourArea: [0, 12],
|
||||||
contourRatio: [0, 12],
|
contourRatio: [0, 12],
|
||||||
contourFullness: [0, 12],
|
contourFullness: [0, 12],
|
||||||
contourSpecklePercentage: 5,
|
contourSpecklePercentage: 5,
|
||||||
|
contourFilterRangeX: 5,
|
||||||
|
contourFilterRangeY: 5,
|
||||||
contourGroupingMode: 0,
|
contourGroupingMode: 0,
|
||||||
contourIntersection: 0,
|
contourIntersection: 0,
|
||||||
contourSortMode: 0,
|
contourSortMode: 0,
|
||||||
@@ -143,6 +156,9 @@ export default new Vuex.Store({
|
|||||||
settings: set('settings'),
|
settings: set('settings'),
|
||||||
calibrationData: set('calibrationData'),
|
calibrationData: set('calibrationData'),
|
||||||
metrics: set('metrics'),
|
metrics: set('metrics'),
|
||||||
|
ntConnectionInfo: set('ntConnectionInfo'),
|
||||||
|
networkInfo: set('networkInfo'),
|
||||||
|
backendConnected: set('backendConnected'),
|
||||||
logString: (state, newStr) => {
|
logString: (state, newStr) => {
|
||||||
const str = state.logMessages;
|
const str = state.logMessages;
|
||||||
str.push(newStr);
|
str.push(newStr);
|
||||||
@@ -245,5 +261,6 @@ export default new Vuex.Store({
|
|||||||
},
|
},
|
||||||
pipelineList: state => state.cameraSettings[state.currentCameraIndex].pipelineNicknames,
|
pipelineList: state => state.cameraSettings[state.currentCameraIndex].pipelineNicknames,
|
||||||
calibrationList: state => state.cameraSettings[state.currentCameraIndex].calibrations,
|
calibrationList: state => state.cameraSettings[state.currentCameraIndex].calibrations,
|
||||||
|
pipelineType: state => state.cameraSettings[state.currentCameraIndex].currentPipelineSettings.pipelineType
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -19,8 +19,8 @@
|
|||||||
<CVselect
|
<CVselect
|
||||||
v-model="currentCameraIndex"
|
v-model="currentCameraIndex"
|
||||||
name="Camera"
|
name="Camera"
|
||||||
select-cols="10"
|
|
||||||
:list="$store.getters.cameraList"
|
:list="$store.getters.cameraList"
|
||||||
|
:select-cols="$vuetify.breakpoint.mdAndUp ? 10 : 7"
|
||||||
@input="handleInput('currentCamera',currentCameraIndex)"
|
@input="handleInput('currentCamera',currentCameraIndex)"
|
||||||
/>
|
/>
|
||||||
<CVnumberinput
|
<CVnumberinput
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
:tooltip="cameraSettings.isFovConfigurable ? 'Field of view (in degrees) of the camera measured across the diagonal of the frame, in a video mode which covers the whole sensor area.' : 'This setting is managed by a vendor'"
|
:tooltip="cameraSettings.isFovConfigurable ? 'Field of view (in degrees) of the camera measured across the diagonal of the frame, in a video mode which covers the whole sensor area.' : 'This setting is managed by a vendor'"
|
||||||
name="Maximum diagonal FOV"
|
name="Maximum diagonal FOV"
|
||||||
:disabled="!cameraSettings.isFovConfigurable"
|
:disabled="!cameraSettings.isFovConfigurable"
|
||||||
|
:label-cols="$vuetify.breakpoint.mdAndUp ? undefined : 7"
|
||||||
/>
|
/>
|
||||||
<br>
|
<br>
|
||||||
<CVnumberinput
|
<CVnumberinput
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
name="Camera pitch"
|
name="Camera pitch"
|
||||||
tooltip="How many degrees above the horizontal the physical camera is tilted"
|
tooltip="How many degrees above the horizontal the physical camera is tilted"
|
||||||
:step="0.01"
|
:step="0.01"
|
||||||
|
:label-cols="$vuetify.breakpoint.mdAndUp ? undefined : 7"
|
||||||
/>
|
/>
|
||||||
<br>
|
<br>
|
||||||
<v-btn
|
<v-btn
|
||||||
@@ -66,43 +68,51 @@
|
|||||||
cols="12"
|
cols="12"
|
||||||
md="6"
|
md="6"
|
||||||
>
|
>
|
||||||
<CVselect
|
<v-form
|
||||||
v-model="selectedFilteredResIndex"
|
ref="form"
|
||||||
name="Resolution"
|
v-model="settingsValid"
|
||||||
select-cols="7"
|
>
|
||||||
:list="stringResolutionList"
|
<CVselect
|
||||||
:disabled="isCalibrating"
|
v-model="selectedFilteredResIndex"
|
||||||
tooltip="Resolution to calibrate at (you will have to calibrate every resolution you use 3D mode on)"
|
name="Resolution"
|
||||||
/>
|
select-cols="7"
|
||||||
<CVselect
|
:list="stringResolutionList"
|
||||||
v-model="boardType"
|
:disabled="isCalibrating"
|
||||||
name="Board Type"
|
tooltip="Resolution to calibrate at (you will have to calibrate every resolution you use 3D mode on)"
|
||||||
select-cols="7"
|
/>
|
||||||
:list="['Chessboard', 'Dot Grid']"
|
<CVselect
|
||||||
:disabled="isCalibrating"
|
v-model="boardType"
|
||||||
tooltip="Calibration board pattern to use"
|
name="Board Type"
|
||||||
/>
|
select-cols="7"
|
||||||
<CVnumberinput
|
:list="['Chessboard', 'Dot Grid']"
|
||||||
v-model="squareSizeIn"
|
:disabled="isCalibrating"
|
||||||
name="Pattern Spacing (in)"
|
tooltip="Calibration board pattern to use"
|
||||||
label-cols="5"
|
/>
|
||||||
tooltip="Spacing between pattern features in inches"
|
<CVnumberinput
|
||||||
:disabled="isCalibrating"
|
v-model="squareSizeIn"
|
||||||
/>
|
name="Pattern Spacing (in)"
|
||||||
<CVnumberinput
|
tooltip="Spacing between pattern features in inches"
|
||||||
v-model="boardWidth"
|
:disabled="isCalibrating"
|
||||||
name="Board width"
|
:rules="[v => (v > 0) || 'Size must be positive']"
|
||||||
label-cols="5"
|
:label-cols="$vuetify.breakpoint.mdAndUp ? 5 : 7"
|
||||||
tooltip="Width of the board in dots or chessboard squares; with the standard chessboard, this is usually 8"
|
/>
|
||||||
:disabled="isCalibrating"
|
<CVnumberinput
|
||||||
/>
|
v-model="boardWidth"
|
||||||
<CVnumberinput
|
name="Board width"
|
||||||
v-model="boardHeight"
|
tooltip="Width of the board in dots or chessboard squares"
|
||||||
name="Board height"
|
:disabled="isCalibrating"
|
||||||
label-cols="5"
|
:rules="[v => (v >= 4) || 'Width must be at least 4']"
|
||||||
tooltip="Height of the board in dots or chessboard squares; with the standard chessboard, this is usually 8"
|
:label-cols="$vuetify.breakpoint.mdAndUp ? 5 : 7"
|
||||||
:disabled="isCalibrating"
|
/>
|
||||||
/>
|
<CVnumberinput
|
||||||
|
v-model="boardHeight"
|
||||||
|
name="Board height"
|
||||||
|
tooltip="Height of the board in dots or chessboard squares"
|
||||||
|
:disabled="isCalibrating"
|
||||||
|
:rules="[v => (v >= 4) || 'Height must be at least 4']"
|
||||||
|
:label-cols="$vuetify.breakpoint.mdAndUp ? 5 : 7"
|
||||||
|
/>
|
||||||
|
</v-form>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- Calibrated table -->
|
<!-- Calibrated table -->
|
||||||
@@ -186,13 +196,24 @@
|
|||||||
@input="e => handlePipelineUpdate('cameraBrightness', e)"
|
@input="e => handlePipelineUpdate('cameraBrightness', e)"
|
||||||
/>
|
/>
|
||||||
<CVslider
|
<CVslider
|
||||||
v-if="$store.getters.currentPipelineSettings.cameraGain !== -1"
|
v-if="$store.getters.currentPipelineSettings.cameraRedGain !== -1"
|
||||||
v-model="$store.getters.currentPipelineSettings.cameraGain"
|
v-model="$store.getters.currentPipelineSettings.cameraRedGain"
|
||||||
name="Gain"
|
name="Red AWB Gain"
|
||||||
:min="0"
|
min="0"
|
||||||
:max="100"
|
max="100"
|
||||||
slider-cols="8"
|
tooltip="Controls red automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||||
@input="e => handlePipelineUpdate('cameraGain', e)"
|
:slider-cols="8"
|
||||||
|
@input="e => handlePipelineData('cameraRedGain', e)"
|
||||||
|
/>
|
||||||
|
<CVslider
|
||||||
|
v-if="$store.getters.currentPipelineSettings.cameraBlueGain !== -1"
|
||||||
|
v-model="$store.getters.currentPipelineSettings.cameraBlueGain"
|
||||||
|
name="Blue AWB Gain"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
tooltip="Controls blue automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||||
|
:slider-cols="8"
|
||||||
|
@input="e => handlePipelineData('cameraBlueGain', e)"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
@@ -227,19 +248,14 @@
|
|||||||
small
|
small
|
||||||
outlined
|
outlined
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
|
:disabled="!settingsValid"
|
||||||
@click="downloadBoard"
|
@click="downloadBoard"
|
||||||
>
|
>
|
||||||
<v-icon left>
|
<v-icon left>
|
||||||
mdi-download
|
mdi-download
|
||||||
</v-icon>
|
</v-icon>
|
||||||
Download Chessboard
|
Download Target
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<a
|
|
||||||
ref="calibrationFile"
|
|
||||||
style="color: black; text-decoration: none; display: none"
|
|
||||||
:href="require('../assets/chessboard.png')"
|
|
||||||
download="chessboard.png"
|
|
||||||
/>
|
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
@@ -325,6 +341,8 @@ import CVnumberinput from '../components/common/cv-number-input';
|
|||||||
import CVslider from '../components/common/cv-slider';
|
import CVslider from '../components/common/cv-slider';
|
||||||
import CVimage from "../components/common/cv-image";
|
import CVimage from "../components/common/cv-image";
|
||||||
import TooltippedLabel from "../components/common/cv-tooltipped-label";
|
import TooltippedLabel from "../components/common/cv-tooltipped-label";
|
||||||
|
import jsPDF from "jspdf";
|
||||||
|
import "../jsPDFFonts/Prompt-Regular-normal.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Cameras',
|
name: 'Cameras',
|
||||||
@@ -341,11 +359,12 @@ export default {
|
|||||||
calibrationInProgress: false,
|
calibrationInProgress: false,
|
||||||
calibrationFailed: false,
|
calibrationFailed: false,
|
||||||
filteredVideomodeIndex: 0,
|
filteredVideomodeIndex: 0,
|
||||||
|
settingsValid: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
disallowCalibration() {
|
disallowCalibration() {
|
||||||
return !(this.calibrationData.boardType === 0 || this.calibrationData.boardType === 1);
|
return !(this.calibrationData.boardType === 0 || this.calibrationData.boardType === 1) || !this.settingsValid;
|
||||||
},
|
},
|
||||||
checkCancellation() {
|
checkCancellation() {
|
||||||
if (this.isCalibrating) {
|
if (this.isCalibrating) {
|
||||||
@@ -486,9 +505,97 @@ export default {
|
|||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
downloadBoard() {
|
downloadBoard() {
|
||||||
this.axios.get("http://" + this.$address + require('../assets/chessboard.png'), {responseType: 'blob'}).then((response) => {
|
// Generates a .pdf of a board for calibration and downloads it
|
||||||
require('downloadjs')(response.data, "Calibration Board", "image/png");
|
|
||||||
});
|
//Murica paper.
|
||||||
|
var doc = new jsPDF({unit: 'in', format:'letter'});
|
||||||
|
var paper_x = 8.5;
|
||||||
|
var paper_y = 11.0;
|
||||||
|
|
||||||
|
//Load in custom fonts
|
||||||
|
console.log(doc.getFontList());
|
||||||
|
doc.setFont('Prompt-Regular');
|
||||||
|
doc.setFontSize(12);
|
||||||
|
|
||||||
|
// Common Parameters
|
||||||
|
var num_x = this.boardWidth;
|
||||||
|
var num_y = this.boardHeight;
|
||||||
|
var patternSize = this.squareSizeIn;
|
||||||
|
var isCheckerboard = (this.boardType==0);
|
||||||
|
|
||||||
|
var x_coord = 0.0;
|
||||||
|
var y_coord = 0.0;
|
||||||
|
var x_idx = 0;
|
||||||
|
var y_idx = 0;
|
||||||
|
var start_x = 0;
|
||||||
|
var start_y = 0;
|
||||||
|
|
||||||
|
var annotation = num_x + " x " + num_y + " | " + patternSize + "in "
|
||||||
|
|
||||||
|
if(isCheckerboard){
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// Checkerboard Pattern
|
||||||
|
|
||||||
|
start_x = paper_x/2.0 - (num_x * patternSize)/2.0;
|
||||||
|
start_y = paper_y/2.0 - (num_y * patternSize)/2.0;
|
||||||
|
|
||||||
|
for(y_idx = 0; y_idx < num_y; y_idx++){
|
||||||
|
for(x_idx = 0; x_idx < num_x; x_idx++){
|
||||||
|
|
||||||
|
x_coord = start_x + x_idx * patternSize;
|
||||||
|
y_coord = start_y + y_idx * patternSize;
|
||||||
|
if((x_idx + y_idx) % 2 == 0){
|
||||||
|
doc.rect(x_coord, y_coord, patternSize, patternSize, "F");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// Assymetric Dot-Grid Pattern
|
||||||
|
// see https://github.com/opencv/opencv/blob/b450dd7a87bc69997a8417d94bdfb87427a9fe62/modules/calib3d/src/circlesgrid.cpp#L437
|
||||||
|
// as well as FindBoardCornersPipe.java's Dotboard implementation
|
||||||
|
|
||||||
|
start_x = paper_x/2.0 - ((2*(num_x-1) + (num_y-1) % 2) * patternSize)/2.0;
|
||||||
|
start_y = paper_y/2.0 - (num_y-1 * patternSize)/2.0;
|
||||||
|
|
||||||
|
// Dot Grid Pattern
|
||||||
|
for(y_idx = 0; y_idx < num_y; y_idx++){
|
||||||
|
for(x_idx = 0; x_idx < num_x; x_idx++){
|
||||||
|
x_coord = start_x + (2*x_idx + y_idx % 2) * patternSize;
|
||||||
|
y_coord = start_y + y_idx * patternSize;
|
||||||
|
doc.circle(x_coord, y_coord, patternSize/4.0, "F");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// Draw a fixed size inch ruler pattern to
|
||||||
|
// help users debug their printers
|
||||||
|
var lineStartX = 1.0;
|
||||||
|
var lineEndX = paper_x - lineStartX;
|
||||||
|
var lineY = paper_y - 1.0;
|
||||||
|
doc.setFont('Prompt-Regular');
|
||||||
|
doc.setLineWidth(0.01);
|
||||||
|
doc.line(lineStartX, lineY, lineEndX, lineY);
|
||||||
|
var segIdx = 0;
|
||||||
|
for(var tickX = lineStartX; tickX <= lineEndX; tickX += 1.0){
|
||||||
|
doc.line(tickX, lineY, tickX, lineY + 0.25);
|
||||||
|
doc.text(String(segIdx) + (segIdx == 0 ? " in" : ""), tickX + 0.1, lineY + 0.25);
|
||||||
|
segIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////
|
||||||
|
// Annotate what was drawn + branding
|
||||||
|
var img = new Image();
|
||||||
|
img.src = require('@/assets/logoMono.png');
|
||||||
|
doc.addImage(img, 'PNG', 1.0, 0.75, 1.4, 0.5 );
|
||||||
|
doc.setFont('Prompt-Regular');
|
||||||
|
doc.text(annotation, paper_x-1.0, 1.0, {maxWidth:(paper_x - 2.0)/2, align:"right"});
|
||||||
|
|
||||||
|
doc.save("calibrationTarget.pdf");
|
||||||
|
|
||||||
},
|
},
|
||||||
sendCameraSettings() {
|
sendCameraSettings() {
|
||||||
this.axios.post("http://" + this.$address + "/api/settings/camera", {
|
this.axios.post("http://" + this.$address + "/api/settings/camera", {
|
||||||
|
|||||||
@@ -30,11 +30,11 @@
|
|||||||
:class="fpsTooLow ? 'ml-2 mt-1' : 'mt-2'"
|
:class="fpsTooLow ? 'ml-2 mt-1' : 'mt-2'"
|
||||||
x-small
|
x-small
|
||||||
label
|
label
|
||||||
:color="fpsTooLow ? 'red' : 'transparent'"
|
:color="fpsTooLow ? 'error' : 'transparent'"
|
||||||
:text-color="fpsTooLow ? 'white' : 'grey'"
|
:text-color="fpsTooLow ? 'white' : 'grey'"
|
||||||
>
|
>
|
||||||
<span class="pr-1">{{ Math.round($store.state.pipelineResults.fps) }} FPS –</span>
|
<span class="pr-1">{{ Math.round($store.state.pipelineResults.fps) }} FPS –</span>
|
||||||
<span v-if="!fpsTooLow">{{ Math.round($store.state.pipelineResults.latency) }} ms latency</span>
|
<span v-if="!fpsTooLow">{{ Math.min(Math.round($store.state.pipelineResults.latency), 100) }} ms latency</span>
|
||||||
<span v-else-if="!$store.getters.currentPipelineSettings.inputShouldShow">HSV thresholds are too broad; narrow them for better performance</span>
|
<span v-else-if="!$store.getters.currentPipelineSettings.inputShouldShow">HSV thresholds are too broad; narrow them for better performance</span>
|
||||||
<span v-else>stop viewing the color stream for better performance</span>
|
<span v-else>stop viewing the color stream for better performance</span>
|
||||||
</v-chip>
|
</v-chip>
|
||||||
@@ -64,7 +64,8 @@
|
|||||||
:disconnected="!$store.state.backendConnected"
|
:disconnected="!$store.state.backendConnected"
|
||||||
scale="100"
|
scale="100"
|
||||||
:max-height="$store.getters.isDriverMode ? '40vh' : '300px'"
|
:max-height="$store.getters.isDriverMode ? '40vh' : '300px'"
|
||||||
:max-height-md="$store.getters.isDriverMode ? '50vh' : '320px'"
|
:max-height-md="$store.getters.isDriverMode ? '50vh' : '380px'"
|
||||||
|
:max-height-lg="$store.getters.isDriverMode ? '55vh' : '390px'"
|
||||||
:max-height-xl="$store.getters.isDriverMode ? '60vh' : '450px'"
|
:max-height-xl="$store.getters.isDriverMode ? '60vh' : '450px'"
|
||||||
:alt="'Stream' + idx"
|
:alt="'Stream' + idx"
|
||||||
:color-picking="$store.state.colorPicking && idx === 0"
|
:color-picking="$store.state.colorPicking && idx === 0"
|
||||||
@@ -84,9 +85,6 @@
|
|||||||
<v-card
|
<v-card
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
<!-- <v-btn @click="onCamNameChange">-->
|
|
||||||
<!-- Reload-->
|
|
||||||
<!-- </v-btn>-->
|
|
||||||
<camera-and-pipeline-select @camera-name-changed="reloadStreams" />
|
<camera-and-pipeline-select @camera-name-changed="reloadStreams" />
|
||||||
</v-card>
|
</v-card>
|
||||||
<v-card
|
<v-card
|
||||||
@@ -98,7 +96,6 @@
|
|||||||
align="center"
|
align="center"
|
||||||
class="pl-3 pr-3"
|
class="pl-3 pr-3"
|
||||||
>
|
>
|
||||||
<!-- -->
|
|
||||||
<v-col lg="12">
|
<v-col lg="12">
|
||||||
<p style="color: white;">
|
<p style="color: white;">
|
||||||
Processing mode:
|
Processing mode:
|
||||||
@@ -198,21 +195,24 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
<!-- snack bar and modal -->
|
|
||||||
<v-snackbar
|
<v-snackbar
|
||||||
v-model="snackbar"
|
v-model="showNTWarning"
|
||||||
:timeout="3000"
|
|
||||||
top
|
|
||||||
color="error"
|
color="error"
|
||||||
|
timeout="-1"
|
||||||
|
top
|
||||||
>
|
>
|
||||||
<span style="color:#000">Can not remove the only pipeline!</span>
|
{{ $store.state.settings.networkSettings.runNTServer ?
|
||||||
<v-btn
|
"NetworkTables server enabled! PhotonLib may not work." :
|
||||||
color="black"
|
"NetworkTables not connected! Are you on a network with a robot?" }}
|
||||||
text
|
<template v-slot:action>
|
||||||
@click="snackbar = false"
|
<v-btn
|
||||||
>
|
text
|
||||||
Close
|
@click="hideNTWarning = true"
|
||||||
</v-btn>
|
>
|
||||||
|
Hide
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
</v-snackbar>
|
</v-snackbar>
|
||||||
|
|
||||||
<v-dialog
|
<v-dialog
|
||||||
@@ -278,10 +278,10 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedTabsData: [0, 0, 0, 0],
|
selectedTabsData: [0, 0, 0, 0],
|
||||||
snackbar: false,
|
|
||||||
counterData: 0,
|
counterData: 0,
|
||||||
dialog: false,
|
dialog: false,
|
||||||
processingModeOverride: false
|
processingModeOverride: false,
|
||||||
|
hideNTWarning: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -421,6 +421,17 @@ export default {
|
|||||||
.some(e => e.width === resolution.width && e.height === resolution.height)
|
.some(e => e.width === resolution.width && e.height === resolution.height)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
isRobotConnected: {
|
||||||
|
get() {
|
||||||
|
// return this.$store.state.ntConnectionInfo.connected && this.$store.state.backendConnected;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showNTWarning: {
|
||||||
|
get() {
|
||||||
|
return (!this.$store.state.ntConnectionInfo.connected || this.$store.state.settings.networkSettings.runNTServer) && this.$store.state.settings.networkSettings.teamNumber > 0 && this.$store.state.backendConnected && !this.hideNTWarning;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.$store.state.connectedCallbacks.push(this.reloadStreams)
|
this.$store.state.connectedCallbacks.push(this.reloadStreams)
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
name="Area"
|
name="Area"
|
||||||
min="0"
|
min="0"
|
||||||
max="100"
|
max="100"
|
||||||
step="0.1"
|
step="0.01"
|
||||||
@input="handlePipelineData('contourArea')"
|
@input="handlePipelineData('contourArea')"
|
||||||
@rollback="e=> rollback('contourArea',e)"
|
|
||||||
/>
|
/>
|
||||||
<CVrangeSlider
|
<CVrangeSlider
|
||||||
|
v-if="currentPipelineType() !== 3"
|
||||||
v-model="contourRatio"
|
v-model="contourRatio"
|
||||||
name="Ratio (W/H)"
|
name="Ratio (W/H)"
|
||||||
tooltip="Min and max ratio between the width and height of a contour's bounding rectangle"
|
tooltip="Min and max ratio between the width and height of a contour's bounding rectangle"
|
||||||
@@ -17,16 +17,32 @@
|
|||||||
max="100"
|
max="100"
|
||||||
step="0.1"
|
step="0.1"
|
||||||
@input="handlePipelineData('contourRatio')"
|
@input="handlePipelineData('contourRatio')"
|
||||||
@rollback="e=> rollback('contourRatio',e)"
|
/>
|
||||||
|
<CVselect
|
||||||
|
v-model="contourTargetOrientation"
|
||||||
|
name="Target Orientation"
|
||||||
|
tooltip="Used to determine how to calculate target landmarks, as well as aspect ratio"
|
||||||
|
:list="['Portrait', 'Landscape']"
|
||||||
|
@input="handlePipelineData('contourTargetOrientation')"
|
||||||
|
@rollback="e=> rollback('contourTargetOrientation', e)"
|
||||||
/>
|
/>
|
||||||
<CVrangeSlider
|
<CVrangeSlider
|
||||||
|
v-if="currentPipelineType() !== 3"
|
||||||
v-model="contourFullness"
|
v-model="contourFullness"
|
||||||
name="Fullness"
|
name="Fullness"
|
||||||
tooltip="Min and max ratio between a contour's area and its bounding rectangle"
|
tooltip="Min and max ratio between a contour's area and its bounding rectangle"
|
||||||
min="0"
|
min="0"
|
||||||
max="100"
|
max="100"
|
||||||
@input="handlePipelineData('contourFullness')"
|
@input="handlePipelineData('contourFullness')"
|
||||||
@rollback="e=> rollback('contourFullness',e)"
|
/>
|
||||||
|
<CVrangeSlider
|
||||||
|
v-if="currentPipelineType() === 3"
|
||||||
|
v-model="contourPerimeter"
|
||||||
|
name="Perimeter"
|
||||||
|
tooltip="Min and max perimeter of the shape, in pixels"
|
||||||
|
min="0"
|
||||||
|
max="4000"
|
||||||
|
@input="handlePipelineData('contourPerimeter')"
|
||||||
/>
|
/>
|
||||||
<CVslider
|
<CVslider
|
||||||
v-model="contourSpecklePercentage"
|
v-model="contourSpecklePercentage"
|
||||||
@@ -36,27 +52,110 @@
|
|||||||
max="100"
|
max="100"
|
||||||
:slider-cols="largeBox"
|
:slider-cols="largeBox"
|
||||||
@input="handlePipelineData('contourSpecklePercentage')"
|
@input="handlePipelineData('contourSpecklePercentage')"
|
||||||
@rollback="e=> rollback('contourSpecklePercentage',e)"
|
|
||||||
/>
|
|
||||||
<CVselect
|
|
||||||
v-model="contourGroupingMode"
|
|
||||||
name="Target Grouping"
|
|
||||||
tooltip="Whether or not every two targets are paired with each other (good for e.g. 2019 targets)"
|
|
||||||
:select-cols="largeBox"
|
|
||||||
:list="['Single','Dual']"
|
|
||||||
@input="handlePipelineData('contourGroupingMode')"
|
|
||||||
@rollback="e=> rollback('contourGroupingMode',e)"
|
|
||||||
/>
|
|
||||||
<CVselect
|
|
||||||
v-model="contourIntersection"
|
|
||||||
name="Target Intersection"
|
|
||||||
tooltip="If target grouping is in dual mode it will use this dropdown to decide how targets are grouped with adjacent targets"
|
|
||||||
:select-cols="largeBox"
|
|
||||||
:list="['None','Up','Down','Left','Right']"
|
|
||||||
:disabled="contourGroupingMode === 0"
|
|
||||||
@input="handlePipelineData('contourIntersection')"
|
|
||||||
@rollback="e=> rollback('contourIntersection',e)"
|
|
||||||
/>
|
/>
|
||||||
|
<template v-if="currentPipelineType() !== 3">
|
||||||
|
<CVslider
|
||||||
|
v-model="contourFilterRangeX"
|
||||||
|
name="X filter tightness"
|
||||||
|
tooltip="Rejects contours whose center X is further than X standard deviations above/below the mean X location"
|
||||||
|
min="0.1"
|
||||||
|
max="4"
|
||||||
|
step="0.1"
|
||||||
|
:slider-cols="largeBox"
|
||||||
|
@input="handlePipelineData('contourFilterRangeX')"
|
||||||
|
/>
|
||||||
|
<CVslider
|
||||||
|
v-model="contourFilterRangeY"
|
||||||
|
name="Y filter tightness"
|
||||||
|
tooltip="Rejects contours whose center Y is further than X standard deviations above/below the mean Y location"
|
||||||
|
min="0.1"
|
||||||
|
max="4"
|
||||||
|
step="0.1"
|
||||||
|
:slider-cols="largeBox"
|
||||||
|
@input="handlePipelineData('contourFilterRangeY')"
|
||||||
|
/>
|
||||||
|
<CVselect
|
||||||
|
v-model="contourGroupingMode"
|
||||||
|
name="Target Grouping"
|
||||||
|
tooltip="Whether or not every two targets are paired with each other (good for e.g. 2019 targets)"
|
||||||
|
:select-cols="largeBox"
|
||||||
|
:list="['Single','Dual','2orMore']"
|
||||||
|
@input="handlePipelineData('contourGroupingMode')"
|
||||||
|
/>
|
||||||
|
<CVselect
|
||||||
|
v-model="contourIntersection"
|
||||||
|
name="Target Intersection"
|
||||||
|
tooltip="If target grouping is in dual mode it will use this dropdown to decide how targets are grouped with adjacent targets"
|
||||||
|
:select-cols="largeBox"
|
||||||
|
:list="['None','Up','Down','Left','Right']"
|
||||||
|
:disabled="contourGroupingMode === 0"
|
||||||
|
@input="handlePipelineData('contourIntersection')"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<!-- If we arent not a shape, we are a shape-->
|
||||||
|
<template v-else>
|
||||||
|
<v-divider class="mt-3" />
|
||||||
|
<CVselect
|
||||||
|
v-model="contourShape"
|
||||||
|
name="Target Shape"
|
||||||
|
tooltip="The shape of targets to look for"
|
||||||
|
:select-cols="largeBox"
|
||||||
|
:list="['Circle', 'Polygon', 'Triangle', 'Quadrilateral']"
|
||||||
|
@input="handlePipelineData('contourShape')"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Accuracy % is only for polygons-->
|
||||||
|
<CVslider
|
||||||
|
v-model="accuracyPercentage"
|
||||||
|
:disabled="currentPipelineSettings().contourShape < 1"
|
||||||
|
name="Shape Simplification"
|
||||||
|
tooltip="How much we should simply the input contour before checking how many sides it has"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
:slider-cols="largeBox"
|
||||||
|
@input="handlePipelineData('accuracyPercentage')"
|
||||||
|
/>
|
||||||
|
<!-- Similarly, the threshold is only for circles -->
|
||||||
|
<CVslider
|
||||||
|
v-model="circleDetectThreshold"
|
||||||
|
:disabled="currentPipelineSettings().contourShape !== 0"
|
||||||
|
name="Circle match distance"
|
||||||
|
tooltip="How close the centroid of a contour must be to the center of a circle in order for them to be matched"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
:slider-cols="largeBox"
|
||||||
|
@input="handlePipelineData('circleDetectThreshold')"
|
||||||
|
/>
|
||||||
|
<CVrangeSlider
|
||||||
|
v-model="contourRadius"
|
||||||
|
:disabled="currentPipelineSettings().contourShape !== 0"
|
||||||
|
name="Radius"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
step="1"
|
||||||
|
label-cols="3"
|
||||||
|
@input="handlePipelineData('contourRadius')"
|
||||||
|
/>
|
||||||
|
<CVslider
|
||||||
|
v-model="maxCannyThresh"
|
||||||
|
:disabled="currentPipelineSettings().contourShape !== 0"
|
||||||
|
name="Max Canny Threshold"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
:slider-cols="largeBox"
|
||||||
|
@input="handlePipelineData('maxCannyThresh')"
|
||||||
|
/>
|
||||||
|
<CVslider
|
||||||
|
v-model="circleAccuracy"
|
||||||
|
:disabled="currentPipelineSettings().contourShape !== 0"
|
||||||
|
name="Circle Accuracy"
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
:slider-cols="largeBox"
|
||||||
|
@input="handlePipelineData('circleAccuracy')"
|
||||||
|
/>
|
||||||
|
<v-divider class="mt-3" />
|
||||||
|
</template>
|
||||||
<CVselect
|
<CVselect
|
||||||
v-model="contourSortMode"
|
v-model="contourSortMode"
|
||||||
name="Target Sort"
|
name="Target Sort"
|
||||||
@@ -70,91 +169,174 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CVrangeSlider from '../../components/common/cv-range-slider'
|
import CVrangeSlider from '../../components/common/cv-range-slider'
|
||||||
import CVselect from '../../components/common/cv-select'
|
import CVselect from '../../components/common/cv-select'
|
||||||
import CVslider from '../../components/common/cv-slider'
|
import CVslider from '../../components/common/cv-slider'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Contours',
|
name: 'Contours',
|
||||||
components: {
|
components: {
|
||||||
CVrangeSlider,
|
CVrangeSlider,
|
||||||
CVselect,
|
CVselect,
|
||||||
CVslider
|
CVslider
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line vue/require-prop-types
|
// eslint-disable-next-line vue/require-prop-types
|
||||||
props: ['value'],
|
props: ['value'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
largeBox: {
|
largeBox: {
|
||||||
get() {
|
get() {
|
||||||
// Sliders and selectors should be fuller width if we're on screen size medium and
|
// Sliders and selectors should be fuller width if we're on screen size medium and
|
||||||
// up and either not in compact mode (because the tab will be 100% screen width),
|
// up and either not in compact mode (because the tab will be 100% screen width),
|
||||||
// or in driver mode (where the card will also be 100% screen width).
|
// or in driver mode (where the card will also be 100% screen width).
|
||||||
return this.$vuetify.breakpoint.mdAndUp && (!this.$store.state.compactMode || this.$store.getters.isDriverMode) ? 10 : 8;
|
return this.$vuetify.breakpoint.mdAndUp && (!this.$store.state.compactMode || this.$store.getters.isDriverMode) ? 10 : 8;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contourArea: {
|
contourArea: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.getters.currentPipelineSettings.contourArea
|
return this.$store.getters.currentPipelineSettings.contourArea
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
this.$store.commit("mutatePipeline", {"contourArea": val});
|
this.$store.commit("mutatePipeline", {"contourArea": val});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contourRatio: {
|
contourRatio: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.getters.currentPipelineSettings.contourRatio
|
return this.$store.getters.currentPipelineSettings.contourRatio
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
this.$store.commit("mutatePipeline", {"contourRatio": val});
|
this.$store.commit("mutatePipeline", {"contourRatio": val});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contourFullness: {
|
contourTargetOrientation: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.getters.currentPipelineSettings.contourFullness
|
return this.$store.getters.currentPipelineSettings.contourTargetOrientation
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
this.$store.commit("mutatePipeline", {"contourFullness": val});
|
this.$store.commit("mutatePipeline", {"contourTargetOrientation": val});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contourSpecklePercentage: {
|
contourFullness: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.getters.currentPipelineSettings.contourSpecklePercentage
|
return this.$store.getters.currentPipelineSettings.contourFullness
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
this.$store.commit("mutatePipeline", {"contourSpecklePercentage": val});
|
this.$store.commit("mutatePipeline", {"contourFullness": val});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contourGroupingMode: {
|
contourPerimeter: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.getters.currentPipelineSettings.contourGroupingMode
|
return this.$store.getters.currentPipelineSettings.contourPerimeter
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
this.$store.commit("mutatePipeline", {"contourGroupingMode": val});
|
this.$store.commit("mutatePipeline", {"contourPerimeter": val});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contourSortMode: {
|
contourSpecklePercentage: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.getters.currentPipelineSettings.contourSortMode
|
return this.$store.getters.currentPipelineSettings.contourSpecklePercentage
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
this.$store.commit("mutatePipeline", {"contourSortMode": val});
|
this.$store.commit("mutatePipeline", {"contourSpecklePercentage": val});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contourIntersection: {
|
contourFilterRangeX: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.getters.currentPipelineSettings.contourIntersection
|
console.log(this.$store.getters.currentPipelineSettings.contourFilterRangeX)
|
||||||
},
|
return this.$store.getters.currentPipelineSettings.contourFilterRangeX
|
||||||
set(val) {
|
},
|
||||||
this.$store.commit("mutatePipeline", {"contourIntersection": val});
|
set(val) {
|
||||||
}
|
console.log("set")
|
||||||
}
|
console.log(val)
|
||||||
},
|
this.$store.commit("mutatePipeline", {"contourFilterRangeX": val});
|
||||||
methods: {},
|
}
|
||||||
}
|
},
|
||||||
|
contourFilterRangeY: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.contourFilterRangeY
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"contourFilterRangeY": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contourGroupingMode: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.contourGroupingMode
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"contourGroupingMode": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contourSortMode: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.contourSortMode
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"contourSortMode": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contourShape: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.contourShape
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"contourShape": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contourIntersection: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.contourIntersection
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"contourIntersection": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
accuracyPercentage: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.accuracyPercentage
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"accuracyPercentage": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contourRadius: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.contourRadius
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"contourRadius": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
circleDetectThreshold: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.circleDetectThreshold
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"circleDetectThreshold": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxCannyThresh: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.maxCannyThresh
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"maxCannyThresh": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
circleAccuracy: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.circleAccuracy
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"circleAccuracy": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="" scoped>
|
<style lang="" scoped>
|
||||||
|
|||||||
@@ -22,15 +22,26 @@
|
|||||||
@rollback="e => rollback('cameraBrightness', e)"
|
@rollback="e => rollback('cameraBrightness', e)"
|
||||||
/>
|
/>
|
||||||
<CVslider
|
<CVslider
|
||||||
v-if="cameraGain !== -1"
|
v-if="cameraRedGain !== -1"
|
||||||
v-model="cameraGain"
|
v-model="cameraRedGain"
|
||||||
name="Gain"
|
name="Red AWB Gain"
|
||||||
min="0"
|
min="0"
|
||||||
max="100"
|
max="100"
|
||||||
tooltip="Controls automatic white balance gain, which affects how the camera captures colors in different conditions"
|
tooltip="Controls red automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||||
:slider-cols="largeBox"
|
:slider-cols="largeBox"
|
||||||
@input="handlePipelineData('cameraGain')"
|
@input="handlePipelineData('cameraRedGain')"
|
||||||
@rollback="e => rollback('cameraGain', e)"
|
@rollback="e => rollback('cameraRedGain', e)"
|
||||||
|
/>
|
||||||
|
<CVslider
|
||||||
|
v-if="cameraBlueGain !== -1"
|
||||||
|
v-model="cameraBlueGain"
|
||||||
|
name="Blue AWB Gain"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
tooltip="Controls blue automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||||
|
:slider-cols="largeBox"
|
||||||
|
@input="handlePipelineData('cameraBlueGain')"
|
||||||
|
@rollback="e => rollback('cameraBlueGain', e)"
|
||||||
/>
|
/>
|
||||||
<CVselect
|
<CVselect
|
||||||
v-model="inputImageRotationMode"
|
v-model="inputImageRotationMode"
|
||||||
@@ -105,12 +116,20 @@
|
|||||||
this.$store.commit("mutatePipeline", {"cameraBrightness": parseInt(val)});
|
this.$store.commit("mutatePipeline", {"cameraBrightness": parseInt(val)});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
cameraGain: {
|
cameraRedGain: {
|
||||||
get() {
|
get() {
|
||||||
return parseInt(this.$store.getters.currentPipelineSettings.cameraGain)
|
return parseInt(this.$store.getters.currentPipelineSettings.cameraRedGain)
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
this.$store.commit("mutatePipeline", {"cameraGain": parseInt(val)});
|
this.$store.commit("mutatePipeline", {"cameraRedGain": parseInt(val)});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cameraBlueGain: {
|
||||||
|
get() {
|
||||||
|
return parseInt(this.$store.getters.currentPipelineSettings.cameraBlueGain)
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"cameraBlueGain": parseInt(val)});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
inputImageRotationMode: {
|
inputImageRotationMode: {
|
||||||
@@ -170,7 +189,11 @@
|
|||||||
// It would probably be cleaner if this checked that we're on the Raspi 3 instead of checking for GPU accel status
|
// It would probably be cleaner if this checked that we're on the Raspi 3 instead of checking for GPU accel status
|
||||||
const width = this.$store.getters.videoFormatList[
|
const width = this.$store.getters.videoFormatList[
|
||||||
this.$store.getters.currentCameraSettings.currentPipelineSettings.cameraVideoModeIndex]['width'];
|
this.$store.getters.currentCameraSettings.currentPipelineSettings.cameraVideoModeIndex]['width'];
|
||||||
return unfilteredStreamDivisors.filter((x) => !this.$store.state.settings.general.gpuAcceleration || width / x < 400);
|
|
||||||
|
// If GPU acceleration is enabled, the downsized width must be below 400px
|
||||||
|
// This check should be skipped if we're currently in driver mode
|
||||||
|
return unfilteredStreamDivisors.filter((x) => this.$store.getters.isDriverMode
|
||||||
|
|| !this.$store.state.settings.general.gpuAcceleration || width / x < 400);
|
||||||
},
|
},
|
||||||
getNumSkippedStreamDivisors() {
|
getNumSkippedStreamDivisors() {
|
||||||
return unfilteredStreamDivisors.length - this.getRawStreamDivisors().length;
|
return unfilteredStreamDivisors.length - this.getRawStreamDivisors().length;
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<span class="white--text">Target Manipulation</span>
|
|
||||||
<v-divider class="mt-2" />
|
|
||||||
|
|
||||||
<CVselect
|
<CVselect
|
||||||
v-model="contourTargetOffsetPointEdge"
|
v-model="contourTargetOffsetPointEdge"
|
||||||
name="Target Offset Point"
|
name="Target Offset Point"
|
||||||
@@ -31,8 +28,7 @@
|
|||||||
|
|
||||||
@rollback="e=> rollback('outputShowMultipleTargets', e)"
|
@rollback="e=> rollback('outputShowMultipleTargets', e)"
|
||||||
/>
|
/>
|
||||||
<span class="white--text">Robot Offset</span>
|
<v-divider />
|
||||||
<v-divider class="mt-2" />
|
|
||||||
<CVselect
|
<CVselect
|
||||||
v-model="offsetRobotOffsetMode"
|
v-model="offsetRobotOffsetMode"
|
||||||
name="Robot Offset Mode"
|
name="Robot Offset Mode"
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
targetList: ['2020 High Goal Outer', '2020 High Goal Inner', '2019 Dual Target', 'Power Cell (7in)', '2016 High Goal'], //Keep in sync with TargetModel.java
|
targetList: ['2020 High Goal Outer', '2020 High Goal Inner', '2019 Dual Target', '2020 Power Cell (7in)','2022 Cargo Ball (9.5in)', '2016 High Goal'], //Keep in sync with TargetModel.java
|
||||||
snackbar: {
|
snackbar: {
|
||||||
color: "Success",
|
color: "Success",
|
||||||
text: ""
|
text: ""
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div :style="{'--averageHue': averageHue}">
|
||||||
<CVrangeSlider
|
<CVrangeSlider
|
||||||
|
id="hue-slider"
|
||||||
v-model="hsvHue"
|
v-model="hsvHue"
|
||||||
|
:class="hueInverted ? 'inverted-slider' : 'normal-slider'"
|
||||||
name="Hue"
|
name="Hue"
|
||||||
tooltip="Describes color"
|
tooltip="Describes color"
|
||||||
:min="0"
|
:min="0"
|
||||||
:max="180"
|
:max="180"
|
||||||
|
:inverted="hueInverted"
|
||||||
@input="handlePipelineData('hsvHue')"
|
@input="handlePipelineData('hsvHue')"
|
||||||
@rollback="e => rollback('hue',e)"
|
@rollback="e => rollback('hue',e)"
|
||||||
/>
|
/>
|
||||||
<CVrangeSlider
|
<CVrangeSlider
|
||||||
|
id="sat-slider"
|
||||||
v-model="hsvSaturation"
|
v-model="hsvSaturation"
|
||||||
|
class="normal-slider"
|
||||||
name="Saturation"
|
name="Saturation"
|
||||||
tooltip="Describes colorfulness; the smaller this value the 'whiter' the color becomes"
|
tooltip="Describes colorfulness; the smaller this value the 'whiter' the color becomes"
|
||||||
:min="0"
|
:min="0"
|
||||||
@@ -19,7 +24,9 @@
|
|||||||
@rollback="e => rollback('saturation',e)"
|
@rollback="e => rollback('saturation',e)"
|
||||||
/>
|
/>
|
||||||
<CVrangeSlider
|
<CVrangeSlider
|
||||||
|
id="value-slider"
|
||||||
v-model="hsvValue"
|
v-model="hsvValue"
|
||||||
|
class="normal-slider"
|
||||||
name="Value"
|
name="Value"
|
||||||
tooltip="Describes lightness; the smaller this value the 'blacker' the color becomes"
|
tooltip="Describes lightness; the smaller this value the 'blacker' the color becomes"
|
||||||
:min="0"
|
:min="0"
|
||||||
@@ -27,6 +34,30 @@
|
|||||||
@input="handlePipelineData('hsvValue')"
|
@input="handlePipelineData('hsvValue')"
|
||||||
@rollback="e => rollback('value',e)"
|
@rollback="e => rollback('value',e)"
|
||||||
/>
|
/>
|
||||||
|
<CVSwitch
|
||||||
|
v-model="hueInverted"
|
||||||
|
name="Invert hue"
|
||||||
|
tooltip="Selects the hue range outside of the hue slider bounds instead of inside"
|
||||||
|
@input="handlePipelineData('hueInverted')"
|
||||||
|
@rollback="e => rollback('hueInverted',e)"
|
||||||
|
/>
|
||||||
|
<template v-if="currentPipelineType() === 3">
|
||||||
|
<CVSwitch
|
||||||
|
v-model="erode"
|
||||||
|
name="Erode"
|
||||||
|
tooltip="Removes pixels around the edges of white areas in the thresholded image"
|
||||||
|
@input="handlePipelineData('erode')"
|
||||||
|
@rollback="e => rollback('erode',e)"
|
||||||
|
/>
|
||||||
|
<CVSwitch
|
||||||
|
v-model="dilate"
|
||||||
|
class="mb-0"
|
||||||
|
name="Dilate"
|
||||||
|
tooltip="Adds pixels around the edges of white areas in the thresholded image"
|
||||||
|
@input="handlePipelineData('dilate')"
|
||||||
|
@rollback="e => rollback('dilate',e)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
<div class="pt-3 white--text">
|
<div class="pt-3 white--text">
|
||||||
Color Picker
|
Color Picker
|
||||||
</div>
|
</div>
|
||||||
@@ -42,7 +73,7 @@
|
|||||||
color="accent"
|
color="accent"
|
||||||
class="ma-2 black--text"
|
class="ma-2 black--text"
|
||||||
small
|
small
|
||||||
@click="setFunction(3)"
|
@click="setFunction(hueInverted ? 2 : 3)"
|
||||||
>
|
>
|
||||||
<v-icon left>
|
<v-icon left>
|
||||||
mdi-minus
|
mdi-minus
|
||||||
@@ -58,13 +89,13 @@
|
|||||||
<v-icon left>
|
<v-icon left>
|
||||||
mdi-plus-minus
|
mdi-plus-minus
|
||||||
</v-icon>
|
</v-icon>
|
||||||
Set To Average
|
{{ hueInverted ? "Exclude" : "Set to" }} Average
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="accent"
|
color="accent"
|
||||||
class="ma-2 black--text"
|
class="ma-2 black--text"
|
||||||
small
|
small
|
||||||
@click="setFunction(2)"
|
@click="setFunction(hueInverted ? 3: 2)"
|
||||||
>
|
>
|
||||||
<v-icon left>
|
<v-icon left>
|
||||||
mdi-plus
|
mdi-plus
|
||||||
@@ -84,116 +115,195 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
<v-divider class="mb-3" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CVrangeSlider from '../../components/common/cv-range-slider'
|
import CVrangeSlider from '../../components/common/cv-range-slider'
|
||||||
|
import CVSwitch from "@/components/common/cv-switch";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Threshold',
|
name: 'Threshold',
|
||||||
components: {
|
components: {
|
||||||
CVrangeSlider
|
CVSwitch,
|
||||||
},
|
CVrangeSlider
|
||||||
// eslint-disable-next-line vue/require-prop-types
|
},
|
||||||
props: ['value'],
|
// eslint-disable-next-line vue/require-prop-types
|
||||||
data() {
|
props: ['value'],
|
||||||
return {
|
data() {
|
||||||
currentFunction: undefined,
|
return {
|
||||||
colorPicker: undefined,
|
currentFunction: undefined,
|
||||||
showThresholdState: 0
|
colorPicker: undefined,
|
||||||
}
|
showThresholdState: 0
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
hsvHue: {
|
|
||||||
get() {
|
|
||||||
return this.$store.getters.currentPipelineSettings.hsvHue
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
this.$store.commit("mutatePipeline", {"hsvHue": val})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hsvSaturation: {
|
|
||||||
get() {
|
|
||||||
return this.$store.getters.currentPipelineSettings.hsvSaturation
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
this.$store.commit("mutatePipeline", {"hsvSaturation": val})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hsvValue: {
|
|
||||||
get() {
|
|
||||||
return this.$store.getters.currentPipelineSettings.hsvValue
|
|
||||||
},
|
|
||||||
set(val) {
|
|
||||||
this.$store.commit("mutatePipeline", {"hsvValue": val})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted: function () {
|
|
||||||
const self = this;
|
|
||||||
this.colorPicker = require('../../plugins/ColorPicker').default;
|
|
||||||
this.$nextTick(() => {
|
|
||||||
self.colorPicker.initColorPicker();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onClick(event) {
|
|
||||||
if (this.currentFunction !== undefined) {
|
|
||||||
this.colorPicker.initColorPicker();
|
|
||||||
|
|
||||||
let s = this.$store.getters.currentPipelineSettings;
|
|
||||||
let hsvArray = this.colorPicker.colorPickerClick(event, this.currentFunction,
|
|
||||||
[
|
|
||||||
[s.hsvHue[0], s.hsvSaturation[0], s.hsvValue[0]],
|
|
||||||
[s.hsvHue[1], s.hsvSaturation[1], s.hsvValue[1]]
|
|
||||||
].map(hsv => hsv.map(it => it || 0)));
|
|
||||||
// That `map` calls are to make sure that we don't let any undefined/null values slip in
|
|
||||||
this.currentFunction = undefined;
|
|
||||||
this.$store.state.colorPicking = false;
|
|
||||||
this.handlePipelineUpdate("outputShouldDraw", true);
|
|
||||||
|
|
||||||
s.hsvHue = [hsvArray[0][0], hsvArray[1][0]];
|
|
||||||
s.hsvSaturation = [hsvArray[0][1], hsvArray[1][1]];
|
|
||||||
s.hsvValue = [hsvArray[0][2], hsvArray[1][2]];
|
|
||||||
|
|
||||||
let msg = this.$msgPack.encode({
|
|
||||||
"changePipelineSetting": {
|
|
||||||
'hsvHue': s.hsvHue,
|
|
||||||
'hsvSaturation': s.hsvSaturation,
|
|
||||||
'hsvValue': s.hsvValue,
|
|
||||||
'cameraIndex': this.$store.state.currentCameraIndex
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.$socket.send(msg);
|
|
||||||
this.$emit('update');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setFunction(index) {
|
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
this.currentFunction = undefined;
|
|
||||||
this.$store.state.colorPicking = false;
|
|
||||||
|
|
||||||
this.handlePipelineUpdate("outputShouldDraw", true);
|
|
||||||
return;
|
|
||||||
case 1:
|
|
||||||
this.currentFunction = this.colorPicker.eyeDrop;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
this.currentFunction = this.colorPicker.expand;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
this.currentFunction = this.colorPicker.shrink;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.$store.state.colorPicking = true;
|
|
||||||
|
|
||||||
this.handlePipelineUpdate("outputShouldDraw", false);
|
|
||||||
this.$store.commit("mutatePipeline", {"inputShouldShow": true});
|
|
||||||
this.handlePipelineUpdate("inputShouldShow", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
hsvHue: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.hsvHue
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"hsvHue": val})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
averageHue: {
|
||||||
|
get() {
|
||||||
|
var isInverted = this.$store.getters.currentPipelineSettings.hueInverted;
|
||||||
|
const arr = this.$store.getters.currentPipelineSettings.hsvHue;
|
||||||
|
var retVal = 0;
|
||||||
|
|
||||||
|
if (Array.isArray(arr)) {
|
||||||
|
retVal = (arr[0] + arr[1]);
|
||||||
|
} else {
|
||||||
|
retVal = (arr.first + arr.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isInverted){
|
||||||
|
retVal += 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(retVal > 360){
|
||||||
|
retVal -= 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hueInverted: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.hueInverted;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"hueInverted": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hsvSaturation: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.hsvSaturation;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"hsvSaturation": val})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hsvValue: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.hsvValue;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"hsvValue": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
erode: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.erode;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"erode": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dilate: {
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.currentPipelineSettings.dilate;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit("mutatePipeline", {"dilate": val});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted: function () {
|
||||||
|
const self = this;
|
||||||
|
this.colorPicker = require('../../plugins/ColorPicker').default;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
self.colorPicker.initColorPicker();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onClick(event) {
|
||||||
|
if (this.currentFunction !== undefined) {
|
||||||
|
this.colorPicker.initColorPicker();
|
||||||
|
|
||||||
|
let s = this.$store.getters.currentPipelineSettings;
|
||||||
|
let hsvArray = this.colorPicker.colorPickerClick(event, this.currentFunction,
|
||||||
|
[
|
||||||
|
[s.hsvHue[0], s.hsvSaturation[0], s.hsvValue[0]],
|
||||||
|
[s.hsvHue[1], s.hsvSaturation[1], s.hsvValue[1]]
|
||||||
|
].map(hsv => hsv.map(it => it || 0)));
|
||||||
|
// That `map` calls are to make sure that we don't let any undefined/null values slip in
|
||||||
|
this.currentFunction = undefined;
|
||||||
|
this.$store.state.colorPicking = false;
|
||||||
|
this.handlePipelineUpdate("outputShouldDraw", true);
|
||||||
|
|
||||||
|
s.hsvHue = [hsvArray[0][0], hsvArray[1][0]];
|
||||||
|
s.hsvSaturation = [hsvArray[0][1], hsvArray[1][1]];
|
||||||
|
s.hsvValue = [hsvArray[0][2], hsvArray[1][2]];
|
||||||
|
|
||||||
|
let msg = this.$msgPack.encode({
|
||||||
|
"changePipelineSetting": {
|
||||||
|
'hsvHue': s.hsvHue,
|
||||||
|
'hsvSaturation': s.hsvSaturation,
|
||||||
|
'hsvValue': s.hsvValue,
|
||||||
|
'cameraIndex': this.$store.state.currentCameraIndex
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.$socket.send(msg);
|
||||||
|
this.$emit('update');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setFunction(index) {
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
this.currentFunction = undefined;
|
||||||
|
this.$store.state.colorPicking = false;
|
||||||
|
|
||||||
|
this.handlePipelineUpdate("outputShouldDraw", true);
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
this.currentFunction = this.colorPicker.eyeDrop;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this.currentFunction = this.colorPicker.expand;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
this.currentFunction = this.colorPicker.shrink;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.$store.state.colorPicking = true;
|
||||||
|
|
||||||
|
this.handlePipelineUpdate("outputShouldDraw", false);
|
||||||
|
this.$store.commit("mutatePipeline", {"inputShouldShow": true});
|
||||||
|
this.handlePipelineUpdate("inputShouldShow", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
#hue-slider >>> .v-slider {
|
||||||
|
background: linear-gradient( to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100% );
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0px 0px 5px #333, inset 0px 0px 3px #333;
|
||||||
|
}
|
||||||
|
#sat-slider >>> .v-slider {
|
||||||
|
background: linear-gradient( to right, #fff 0%, hsl(var(--averageHue), 100%, 50%) 100% );
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0px 0px 5px #333, inset 0px 0px 3px #333;
|
||||||
|
}
|
||||||
|
#value-slider >>> .v-slider {
|
||||||
|
background: linear-gradient( to right, #000 0%, hsl(var(--averageHue), 100%, 50%) 100% );
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0px 0px 5px #333, inset 0px 0px 3px #333;
|
||||||
|
}
|
||||||
|
>>> .v-slider__thumb {
|
||||||
|
outline: black solid thin;
|
||||||
|
}
|
||||||
|
.normal-slider >>> .v-slider__track-fill {
|
||||||
|
outline: black solid thin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inverted-slider >>> .v-slider__track-background {
|
||||||
|
outline: black solid thin;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
return {
|
return {
|
||||||
selectedTab: 0,
|
selectedTab: 0,
|
||||||
snack: false,
|
snack: false,
|
||||||
|
calibrationInProgress: false,
|
||||||
snackbar: {
|
snackbar: {
|
||||||
color: "accent",
|
color: "accent",
|
||||||
text: ""
|
text: ""
|
||||||
|
|||||||
@@ -91,7 +91,7 @@
|
|||||||
<v-col
|
<v-col
|
||||||
cols="12"
|
cols="12"
|
||||||
sm="6"
|
sm="6"
|
||||||
lg="3"
|
md="4"
|
||||||
>
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="secondary"
|
color="secondary"
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
<v-col
|
<v-col
|
||||||
cols="12"
|
cols="12"
|
||||||
sm="6"
|
sm="6"
|
||||||
lg="3"
|
md="4"
|
||||||
>
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="secondary"
|
color="secondary"
|
||||||
@@ -120,7 +120,21 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
<v-col
|
<v-col
|
||||||
cols="12"
|
cols="12"
|
||||||
lg="3"
|
md="4"
|
||||||
|
>
|
||||||
|
<v-btn
|
||||||
|
color="secondary"
|
||||||
|
@click="$refs.offlineUpdate.click()"
|
||||||
|
>
|
||||||
|
<v-icon left>
|
||||||
|
mdi-update
|
||||||
|
</v-icon>
|
||||||
|
Offline Update
|
||||||
|
</v-btn>
|
||||||
|
</v-col>
|
||||||
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
lg="6"
|
||||||
>
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="red"
|
color="red"
|
||||||
@@ -129,19 +143,19 @@
|
|||||||
<v-icon left>
|
<v-icon left>
|
||||||
mdi-restart
|
mdi-restart
|
||||||
</v-icon>
|
</v-icon>
|
||||||
Restart Photon
|
Restart PhotonVision
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col
|
<v-col
|
||||||
cols="12"
|
cols="12"
|
||||||
lg="3"
|
lg="6"
|
||||||
>
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="red"
|
color="red"
|
||||||
@click="restartDevice()"
|
@click="restartDevice()"
|
||||||
>
|
>
|
||||||
<v-icon left>
|
<v-icon left>
|
||||||
mdi-restart
|
mdi-restart-alert
|
||||||
</v-icon>
|
</v-icon>
|
||||||
Restart Device
|
Restart Device
|
||||||
</v-btn>
|
</v-btn>
|
||||||
@@ -172,6 +186,15 @@
|
|||||||
:href="'http://' + this.$address + '/api/settings/photonvision_config.zip'"
|
:href="'http://' + this.$address + '/api/settings/photonvision_config.zip'"
|
||||||
download="photonvision-settings.zip"
|
download="photonvision-settings.zip"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Special hidden new jar upload input that gets 'clicked' when the user posts a new .jar -->
|
||||||
|
<input
|
||||||
|
ref="offlineUpdate"
|
||||||
|
type="file"
|
||||||
|
accept=".jar"
|
||||||
|
style="display: none;"
|
||||||
|
@change="doOfflineUpdate"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -181,6 +204,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
snack: false,
|
snack: false,
|
||||||
|
uploadPercentage: 0.0,
|
||||||
snackbar: {
|
snackbar: {
|
||||||
color: "success",
|
color: "success",
|
||||||
text: ""
|
text: ""
|
||||||
@@ -226,7 +250,7 @@ export default {
|
|||||||
{headers: {"Content-Type": "multipart/form-data"}}).then(() => {
|
{headers: {"Content-Type": "multipart/form-data"}}).then(() => {
|
||||||
this.snackbar = {
|
this.snackbar = {
|
||||||
color: "success",
|
color: "success",
|
||||||
text: "Settings imported successfully! Program will now exit...",
|
text: "Settings imported successfully! PhotonVision will restart in the background...",
|
||||||
};
|
};
|
||||||
this.snack = true;
|
this.snack = true;
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
@@ -249,6 +273,52 @@ export default {
|
|||||||
this.snack = true;
|
this.snack = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
doOfflineUpdate(event) {
|
||||||
|
this.snackbar = {
|
||||||
|
color: "secondary",
|
||||||
|
text: "New Software Upload in Process..."
|
||||||
|
};
|
||||||
|
this.snack = true;
|
||||||
|
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append("jarData", event.target.files[0]);
|
||||||
|
this.axios.post("http://" + this.$address + "/api/settings/offlineUpdate", formData,
|
||||||
|
{headers: {"Content-Type": "multipart/form-data"},
|
||||||
|
onUploadProgress: function( progressEvent ) {
|
||||||
|
this.uploadPercentage = parseInt( Math.round( ( progressEvent.loaded / progressEvent.total ) * 100 ) );
|
||||||
|
if(this.uploadPercentage < 99.5){
|
||||||
|
this.snackbar.text = "New Software Upload in Process, " + this.uploadPercentage + "% complete";
|
||||||
|
} else {
|
||||||
|
this.snackbar.text = "Installing uploaded software...";
|
||||||
|
}
|
||||||
|
|
||||||
|
}.bind(this)
|
||||||
|
}).then(() => {
|
||||||
|
this.snackbar = {
|
||||||
|
color: "success",
|
||||||
|
text: "New .jar copied successfully! PhotonVision will restart in the background...",
|
||||||
|
};
|
||||||
|
this.snack = true;
|
||||||
|
}).catch(err => {
|
||||||
|
if (err.response) {
|
||||||
|
this.snackbar = {
|
||||||
|
color: "error",
|
||||||
|
text: "Error while uploading new .jar file! Could not process provided file.",
|
||||||
|
};
|
||||||
|
} else if (err.request) {
|
||||||
|
this.snackbar = {
|
||||||
|
color: "error",
|
||||||
|
text: "Error while uploading new .jar file! No respond to upload attempt.",
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.snackbar = {
|
||||||
|
color: "error",
|
||||||
|
text: "Error while uploading new .jar file!",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.snack = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -266,6 +336,8 @@ export default {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.infoElem {
|
.infoElem {
|
||||||
|
|||||||
@@ -4,46 +4,127 @@
|
|||||||
ref="form"
|
ref="form"
|
||||||
v-model="valid"
|
v-model="valid"
|
||||||
>
|
>
|
||||||
<CVSwitch
|
|
||||||
v-model="runNTServer"
|
|
||||||
name="Run NetworkTables Server"
|
|
||||||
tooltip="If enabled, this device will create a NT server. This is useful for home debugging, but should be disabled on-robot."
|
|
||||||
/>
|
|
||||||
<CVnumberinput
|
<CVnumberinput
|
||||||
v-model="teamNumber"
|
v-model="teamNumber"
|
||||||
:disabled="settings.runNTServer"
|
:disabled="settings.runNTServer"
|
||||||
name="Team Number"
|
name="Team Number"
|
||||||
:rules="[v => (v > 0) || 'Team number must be greater than zero', v => (v < 10000) || 'Team number must have fewer than five digits']"
|
:rules="[v => (v > 0) || 'Team number must be greater than zero', v => (v < 10000) || 'Team number must have fewer than five digits']"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
|
:label-cols="$vuetify.breakpoint.mdAndUp ? undefined : 5"
|
||||||
/>
|
/>
|
||||||
|
<v-banner
|
||||||
|
v-show="(teamNumber < 1 || teamNumber > 10000) && !runNTServer"
|
||||||
|
rounded
|
||||||
|
color="red"
|
||||||
|
text-color="white"
|
||||||
|
>
|
||||||
|
Team number is unset or invalid. NetworkTables will not be able to connect.
|
||||||
|
</v-banner>
|
||||||
<CVradio
|
<CVradio
|
||||||
|
v-show="$store.state.settings.networkSettings.supported"
|
||||||
v-model="connectionType"
|
v-model="connectionType"
|
||||||
|
:input-cols="inputCols"
|
||||||
|
name="IP Assignment Mode"
|
||||||
|
tooltip="DHCP will make the radio (router) automatically assign an IP address; this may result in an IP address that changes across reboots. Static IP assignment means that you pick the IP address and it won't change."
|
||||||
:list="['DHCP','Static']"
|
:list="['DHCP','Static']"
|
||||||
:disabled="!$store.state.settings.networkSettings.supported"
|
|
||||||
/>
|
/>
|
||||||
<template v-if="!isDHCP">
|
<CVinput
|
||||||
<CVinput
|
v-if="!isDHCP"
|
||||||
v-model="staticIp"
|
v-model="staticIp"
|
||||||
:input-cols="inputCols"
|
:input-cols="inputCols"
|
||||||
:rules="[v => isIPv4(v) || 'Invalid IPv4 address']"
|
:rules="[v => isIPv4(v) || 'Invalid IPv4 address']"
|
||||||
name="IP"
|
name="IP"
|
||||||
/>
|
/>
|
||||||
</template>
|
|
||||||
<CVinput
|
<CVinput
|
||||||
v-model="hostname"
|
v-model="hostname"
|
||||||
:input-cols="inputCols"
|
:input-cols="inputCols"
|
||||||
:rules="[v => isHostname(v) || 'Invalid hostname']"
|
:rules="[v => isHostname(v) || 'Invalid hostname']"
|
||||||
name="Hostname"
|
name="Hostname"
|
||||||
/>
|
/>
|
||||||
|
<CVSwitch
|
||||||
|
v-model="runNTServer"
|
||||||
|
name="Run NetworkTables Server (Debugging Only)"
|
||||||
|
tooltip="If enabled, this device will create a NT server. This is useful for home debugging, but should be disabled on-robot."
|
||||||
|
class="mt-3 mb-3"
|
||||||
|
:text-cols="$vuetify.breakpoint.mdAndUp ? undefined : 5"
|
||||||
|
/>
|
||||||
|
<v-banner
|
||||||
|
v-show="runNTServer"
|
||||||
|
rounded
|
||||||
|
color="red"
|
||||||
|
text-color="white"
|
||||||
|
>
|
||||||
|
This switch is intended for testing; it should be off on a robot. PhotonLib will NOT work!
|
||||||
|
</v-banner>
|
||||||
</v-form>
|
</v-form>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="accent"
|
color="accent"
|
||||||
|
:class="runNTServer ? 'mt-3' : ''"
|
||||||
style="color: black; width: 100%;"
|
style="color: black; width: 100%;"
|
||||||
:disabled="!valid && !runNTServer"
|
:disabled="!valid && !runNTServer"
|
||||||
@click="sendGeneralSettings()"
|
@click="sendGeneralSettings()"
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
<v-divider class="mt-4 mb-4" />
|
||||||
|
<v-row>
|
||||||
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
sm="6"
|
||||||
|
>
|
||||||
|
<v-simple-table
|
||||||
|
fixed-header
|
||||||
|
height="100%"
|
||||||
|
dense
|
||||||
|
>
|
||||||
|
<template v-slot:default>
|
||||||
|
<thead style="font-size: 1.25rem;">
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Device IPs
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(value, index) in $store.state.networkInfo.deviceips"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</template>
|
||||||
|
</v-simple-table>
|
||||||
|
</v-col>
|
||||||
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
sm="6"
|
||||||
|
>
|
||||||
|
<v-simple-table
|
||||||
|
fixed-header
|
||||||
|
height="100%"
|
||||||
|
dense
|
||||||
|
>
|
||||||
|
<template v-slot:default>
|
||||||
|
<thead style="font-size: 1.25rem;">
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Possible RoboRIOs
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(value, index) in $store.state.networkInfo.possibleRios"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</template>
|
||||||
|
</v-simple-table>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -80,7 +161,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
inputCols() {
|
inputCols() {
|
||||||
return this.$vuetify.breakpoint.smAndUp ? 10 : 7;
|
return this.$vuetify.breakpoint.mdAndUp ? 10 : 7;
|
||||||
},
|
},
|
||||||
isDHCP() {
|
isDHCP() {
|
||||||
return this.settings.connectionType === 0;
|
return this.settings.connectionType === 0;
|
||||||
@@ -179,6 +260,24 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="" scoped>
|
<style scoped>
|
||||||
|
.v-data-table {
|
||||||
|
/*text-align: center;*/
|
||||||
|
background-color: transparent !important;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-data-table th {
|
||||||
|
background-color: #006492 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-data-table th, td {
|
||||||
|
font-size: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-data-table td {
|
||||||
|
font-family: monospace !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
13
photon-core/.gitignore
vendored
Normal file
13
photon-core/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
bin/*
|
||||||
|
.settings/*
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
*.prefs
|
||||||
|
.gradle
|
||||||
|
.gradle/*
|
||||||
|
build
|
||||||
|
build/*
|
||||||
|
photonvision/*
|
||||||
|
photonvision_config/*
|
||||||
|
|
||||||
|
src/main/java/org/photonvision/PhotonVersion.java
|
||||||
33
photon-core/build.gradle
Normal file
33
photon-core/build.gradle
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
apply from: "${rootDir}/shared/common.gradle"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':photon-targeting')
|
||||||
|
|
||||||
|
implementation 'io.javalin:javalin:4.2.0'
|
||||||
|
|
||||||
|
implementation 'org.msgpack:msgpack-core:0.9.0'
|
||||||
|
implementation 'org.msgpack:jackson-dataformat-msgpack:0.9.0'
|
||||||
|
|
||||||
|
// wpiutil
|
||||||
|
jniPlatforms.each { implementation "edu.wpi.first.wpiutil:wpiutil-jni:$wpilibVersion:$it" }
|
||||||
|
|
||||||
|
// JOGL stuff (currently we only distribute for aarch64, which is Pi 4)
|
||||||
|
implementation "org.jogamp.gluegen:gluegen-rt:$joglVersion"
|
||||||
|
implementation "org.jogamp.jogl:jogl-all:$joglVersion"
|
||||||
|
|
||||||
|
implementation "org.jogamp.gluegen:gluegen-rt:$joglVersion:natives-linux-aarch64"
|
||||||
|
implementation "org.jogamp.jogl:jogl-all:$joglVersion:natives-linux-aarch64"
|
||||||
|
|
||||||
|
// Zip
|
||||||
|
implementation 'org.zeroturnaround:zt-zip:1.14'
|
||||||
|
}
|
||||||
|
|
||||||
|
task writeCurrentVersionJava {
|
||||||
|
def versionFileIn = file("${rootDir}/shared/PhotonVersion.java.in")
|
||||||
|
writePhotonVersionFile(versionFileIn, Path.of("$projectDir", "src", "main", "java", "org", "photonvision", "PhotonVersion.java"),
|
||||||
|
versionString)
|
||||||
|
}
|
||||||
|
|
||||||
|
build.dependsOn writeCurrentVersionJava
|
||||||
1
photon-core/settings.gradle
Normal file
1
photon-core/settings.gradle
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'photon-core'
|
||||||
@@ -20,7 +20,7 @@ package org.photonvision.common.configuration;
|
|||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import edu.wpi.first.wpilibj.geometry.Rotation2d;
|
import edu.wpi.first.math.geometry.Rotation2d;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.photonvision.common.logging.LogGroup;
|
import org.photonvision.common.logging.LogGroup;
|
||||||
@@ -32,7 +32,6 @@ import java.util.*;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.photonvision.common.logging.LogGroup;
|
import org.photonvision.common.logging.LogGroup;
|
||||||
import org.photonvision.common.logging.Logger;
|
import org.photonvision.common.logging.Logger;
|
||||||
import org.photonvision.common.util.TimedTaskManager;
|
|
||||||
import org.photonvision.common.util.file.FileUtils;
|
import org.photonvision.common.util.file.FileUtils;
|
||||||
import org.photonvision.common.util.file.JacksonUtils;
|
import org.photonvision.common.util.file.JacksonUtils;
|
||||||
import org.photonvision.vision.pipeline.CVPipelineSettings;
|
import org.photonvision.vision.pipeline.CVPipelineSettings;
|
||||||
@@ -57,6 +56,7 @@ public class ConfigManager {
|
|||||||
final File configDirectoryFile;
|
final File configDirectoryFile;
|
||||||
|
|
||||||
private long saveRequestTimestamp = -1;
|
private long saveRequestTimestamp = -1;
|
||||||
|
private Thread settingsSaveThread;
|
||||||
|
|
||||||
public static ConfigManager getInstance() {
|
public static ConfigManager getInstance() {
|
||||||
if (INSTANCE == null) {
|
if (INSTANCE == null) {
|
||||||
@@ -97,7 +97,8 @@ public class ConfigManager {
|
|||||||
new File(Path.of(configDirectoryFile.toString(), NET_SET_FNAME).toUri());
|
new File(Path.of(configDirectoryFile.toString(), NET_SET_FNAME).toUri());
|
||||||
this.camerasFolder = new File(Path.of(configDirectoryFile.toString(), "cameras").toUri());
|
this.camerasFolder = new File(Path.of(configDirectoryFile.toString(), "cameras").toUri());
|
||||||
|
|
||||||
TimedTaskManager.getInstance().addTask("ConfigManager", this::checkSaveAndWrite, 1000);
|
settingsSaveThread = new Thread(this::saveAndWriteTask);
|
||||||
|
settingsSaveThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load() {
|
public void load() {
|
||||||
@@ -332,8 +333,8 @@ public class ConfigManager {
|
|||||||
return loadedConfigurations;
|
return loadedConfigurations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCameraConfigurations(HashMap<VisionSource, CameraConfiguration> sources) {
|
public void addCameraConfigurations(List<VisionSource> sources) {
|
||||||
getConfig().addCameraConfigs(sources.values());
|
getConfig().addCameraConfigs(sources);
|
||||||
requestSave();
|
requestSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,12 +426,24 @@ public class ConfigManager {
|
|||||||
saveRequestTimestamp = System.currentTimeMillis();
|
saveRequestTimestamp = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSaveAndWrite() {
|
private void saveAndWriteTask() {
|
||||||
// Only save if 1 second has past since the request was made
|
// Only save if 1 second has past since the request was made
|
||||||
if (saveRequestTimestamp > 0 && (System.currentTimeMillis() - saveRequestTimestamp) > 1000L) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
saveRequestTimestamp = -1;
|
if (saveRequestTimestamp > 0 && (System.currentTimeMillis() - saveRequestTimestamp) > 1000L) {
|
||||||
logger.debug("Saving to disk...");
|
saveRequestTimestamp = -1;
|
||||||
saveToDisk();
|
logger.debug("Saving to disk...");
|
||||||
|
saveToDisk();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error("Exception waiting for settings semaphor", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void unloadCameraConfigs() {
|
||||||
|
this.config.getCameraConfigurations().clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,6 @@ import java.util.List;
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class HardwareConfig {
|
public class HardwareConfig {
|
||||||
|
|
||||||
public final String deviceName;
|
public final String deviceName;
|
||||||
public final String deviceLogoPath;
|
public final String deviceLogoPath;
|
||||||
public final String supportURL;
|
public final String supportURL;
|
||||||
@@ -28,10 +28,10 @@ import org.photonvision.common.util.SerializationUtils;
|
|||||||
import org.photonvision.raspi.PicamJNI;
|
import org.photonvision.raspi.PicamJNI;
|
||||||
import org.photonvision.vision.processes.VisionModule;
|
import org.photonvision.vision.processes.VisionModule;
|
||||||
import org.photonvision.vision.processes.VisionModuleManager;
|
import org.photonvision.vision.processes.VisionModuleManager;
|
||||||
|
import org.photonvision.vision.processes.VisionSource;
|
||||||
|
|
||||||
// TODO rename this class
|
// TODO rename this class
|
||||||
public class PhotonConfiguration {
|
public class PhotonConfiguration {
|
||||||
|
|
||||||
private HardwareConfig hardwareConfig;
|
private HardwareConfig hardwareConfig;
|
||||||
private HardwareSettings hardwareSettings;
|
private HardwareSettings hardwareSettings;
|
||||||
private NetworkConfig networkConfig;
|
private NetworkConfig networkConfig;
|
||||||
@@ -75,9 +75,9 @@ public class PhotonConfiguration {
|
|||||||
return cameraConfigurations;
|
return cameraConfigurations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCameraConfigs(Collection<CameraConfiguration> config) {
|
public void addCameraConfigs(Collection<VisionSource> sources) {
|
||||||
for (var c : config) {
|
for (var s : sources) {
|
||||||
addCameraConfig(c);
|
addCameraConfig(s.getCameraConfiguration());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +27,6 @@ import org.photonvision.common.logging.Logger;
|
|||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public class DataChangeService {
|
public class DataChangeService {
|
||||||
|
|
||||||
private static final Logger logger = new Logger(DataChangeService.class, LogGroup.WebServer);
|
private static final Logger logger = new Logger(DataChangeService.class, LogGroup.WebServer);
|
||||||
|
|
||||||
private static class ThreadSafeSingleton {
|
private static class ThreadSafeSingleton {
|
||||||
@@ -23,7 +23,6 @@ import org.photonvision.common.dataflow.DataChangeDestination;
|
|||||||
import org.photonvision.common.dataflow.DataChangeSource;
|
import org.photonvision.common.dataflow.DataChangeSource;
|
||||||
|
|
||||||
public class IncomingWebSocketEvent<T> extends DataChangeEvent<T> {
|
public class IncomingWebSocketEvent<T> extends DataChangeEvent<T> {
|
||||||
|
|
||||||
public final Integer cameraIndex;
|
public final Integer cameraIndex;
|
||||||
public final WsContext originContext;
|
public final WsContext originContext;
|
||||||
|
|
||||||
@@ -34,6 +34,13 @@ public class OutgoingUIEvent<T> extends DataChangeEvent<T> {
|
|||||||
this.originContext = originContext;
|
this.originContext = originContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static OutgoingUIEvent<HashMap<String, Object>> wrappedOf(
|
||||||
|
String commandName, Object value) {
|
||||||
|
HashMap<String, Object> data = new HashMap<>();
|
||||||
|
data.put(commandName, value);
|
||||||
|
return new OutgoingUIEvent<>(commandName, data);
|
||||||
|
}
|
||||||
|
|
||||||
public static OutgoingUIEvent<HashMap<String, Object>> wrappedOf(
|
public static OutgoingUIEvent<HashMap<String, Object>> wrappedOf(
|
||||||
String commandName, String propertyName, Object value, WsContext originContext) {
|
String commandName, String propertyName, Object value, WsContext originContext) {
|
||||||
HashMap<String, Object> data = new HashMap<>();
|
HashMap<String, Object> data = new HashMap<>();
|
||||||
@@ -23,7 +23,6 @@ import edu.wpi.first.networktables.NetworkTableEntry;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class NTDataChangeListener {
|
public class NTDataChangeListener {
|
||||||
|
|
||||||
private final NetworkTableEntry watchedEntry;
|
private final NetworkTableEntry watchedEntry;
|
||||||
private final int listenerID;
|
private final int listenerID;
|
||||||
|
|
||||||
@@ -20,16 +20,21 @@ package org.photonvision.common.dataflow.networktables;
|
|||||||
import edu.wpi.first.networktables.EntryNotification;
|
import edu.wpi.first.networktables.EntryNotification;
|
||||||
import edu.wpi.first.networktables.NetworkTable;
|
import edu.wpi.first.networktables.NetworkTable;
|
||||||
import edu.wpi.first.networktables.NetworkTableEntry;
|
import edu.wpi.first.networktables.NetworkTableEntry;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import org.opencv.core.Point;
|
||||||
import org.photonvision.common.dataflow.CVPipelineResultConsumer;
|
import org.photonvision.common.dataflow.CVPipelineResultConsumer;
|
||||||
import org.photonvision.common.dataflow.structures.Packet;
|
import org.photonvision.common.dataflow.structures.Packet;
|
||||||
|
import org.photonvision.targeting.PhotonPipelineResult;
|
||||||
|
import org.photonvision.targeting.PhotonTrackedTarget;
|
||||||
|
import org.photonvision.targeting.TargetCorner;
|
||||||
import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
||||||
import org.photonvision.vision.pipeline.result.SimplePipelineResult;
|
import org.photonvision.vision.target.TrackedTarget;
|
||||||
|
|
||||||
public class NTDataPublisher implements CVPipelineResultConsumer {
|
public class NTDataPublisher implements CVPipelineResultConsumer {
|
||||||
|
|
||||||
private final NetworkTable rootTable = NetworkTablesManager.getInstance().kRootTable;
|
private final NetworkTable rootTable = NetworkTablesManager.getInstance().kRootTable;
|
||||||
private NetworkTable subTable;
|
private NetworkTable subTable;
|
||||||
private NetworkTableEntry rawBytesEntry;
|
private NetworkTableEntry rawBytesEntry;
|
||||||
@@ -163,7 +168,9 @@ public class NTDataPublisher implements CVPipelineResultConsumer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(CVPipelineResult result) {
|
public void accept(CVPipelineResult result) {
|
||||||
var simplified = new SimplePipelineResult(result);
|
var simplified =
|
||||||
|
new PhotonPipelineResult(
|
||||||
|
result.getLatencyMillis(), simpleFromTrackedTargets(result.targets));
|
||||||
Packet packet = new Packet(simplified.getPacketSize());
|
Packet packet = new Packet(simplified.getPacketSize());
|
||||||
simplified.populatePacket(packet);
|
simplified.populatePacket(packet);
|
||||||
|
|
||||||
@@ -201,4 +208,25 @@ public class NTDataPublisher implements CVPipelineResultConsumer {
|
|||||||
}
|
}
|
||||||
rootTable.getInstance().flush();
|
rootTable.getInstance().flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<PhotonTrackedTarget> simpleFromTrackedTargets(List<TrackedTarget> targets) {
|
||||||
|
var ret = new ArrayList<PhotonTrackedTarget>();
|
||||||
|
for (var t : targets) {
|
||||||
|
var points = new Point[4];
|
||||||
|
t.getMinAreaRect().points(points);
|
||||||
|
var cornerList = new ArrayList<TargetCorner>();
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) cornerList.add(new TargetCorner(points[i].x, points[i].y));
|
||||||
|
|
||||||
|
ret.add(
|
||||||
|
new PhotonTrackedTarget(
|
||||||
|
t.getYaw(),
|
||||||
|
t.getPitch(),
|
||||||
|
t.getArea(),
|
||||||
|
t.getSkew(),
|
||||||
|
t.getCameraToTarget(),
|
||||||
|
cornerList));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,15 +20,19 @@ package org.photonvision.common.dataflow.networktables;
|
|||||||
import edu.wpi.first.networktables.LogMessage;
|
import edu.wpi.first.networktables.LogMessage;
|
||||||
import edu.wpi.first.networktables.NetworkTable;
|
import edu.wpi.first.networktables.NetworkTable;
|
||||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import org.photonvision.PhotonVersion;
|
||||||
import org.photonvision.common.configuration.NetworkConfig;
|
import org.photonvision.common.configuration.NetworkConfig;
|
||||||
|
import org.photonvision.common.dataflow.DataChangeService;
|
||||||
|
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||||
import org.photonvision.common.logging.LogGroup;
|
import org.photonvision.common.logging.LogGroup;
|
||||||
import org.photonvision.common.logging.Logger;
|
import org.photonvision.common.logging.Logger;
|
||||||
import org.photonvision.common.scripting.ScriptEventType;
|
import org.photonvision.common.scripting.ScriptEventType;
|
||||||
import org.photonvision.common.scripting.ScriptManager;
|
import org.photonvision.common.scripting.ScriptManager;
|
||||||
|
import org.photonvision.common.util.TimedTaskManager;
|
||||||
|
|
||||||
public class NetworkTablesManager {
|
public class NetworkTablesManager {
|
||||||
|
|
||||||
private final NetworkTableInstance ntInstance = NetworkTableInstance.getDefault();
|
private final NetworkTableInstance ntInstance = NetworkTableInstance.getDefault();
|
||||||
private final String kRootTableName = "/photonvision";
|
private final String kRootTableName = "/photonvision";
|
||||||
public final NetworkTable kRootTable = ntInstance.getTable(kRootTableName);
|
public final NetworkTable kRootTable = ntInstance.getTable(kRootTableName);
|
||||||
@@ -47,7 +51,6 @@ public class NetworkTablesManager {
|
|||||||
private static final Logger logger = new Logger(NetworkTablesManager.class, LogGroup.General);
|
private static final Logger logger = new Logger(NetworkTablesManager.class, LogGroup.General);
|
||||||
|
|
||||||
private static class NTLogger implements Consumer<LogMessage> {
|
private static class NTLogger implements Consumer<LogMessage> {
|
||||||
|
|
||||||
private boolean hasReportedConnectionFailure = false;
|
private boolean hasReportedConnectionFailure = false;
|
||||||
private long lastConnectMessageMillis = 0;
|
private long lastConnectMessageMillis = 0;
|
||||||
|
|
||||||
@@ -56,22 +59,53 @@ public class NetworkTablesManager {
|
|||||||
if (!hasReportedConnectionFailure && logMessage.message.contains("timed out")) {
|
if (!hasReportedConnectionFailure && logMessage.message.contains("timed out")) {
|
||||||
logger.error("NT Connection has failed! Will retry in background.");
|
logger.error("NT Connection has failed! Will retry in background.");
|
||||||
hasReportedConnectionFailure = true;
|
hasReportedConnectionFailure = true;
|
||||||
|
getInstance().broadcastConnectedStatus();
|
||||||
} else if (logMessage.message.contains("connected")
|
} else if (logMessage.message.contains("connected")
|
||||||
&& System.currentTimeMillis() - lastConnectMessageMillis > 125) {
|
&& System.currentTimeMillis() - lastConnectMessageMillis > 125) {
|
||||||
logger.info("NT Connected!");
|
logger.info("NT Connected!");
|
||||||
hasReportedConnectionFailure = false;
|
hasReportedConnectionFailure = false;
|
||||||
lastConnectMessageMillis = System.currentTimeMillis();
|
lastConnectMessageMillis = System.currentTimeMillis();
|
||||||
ScriptManager.queueEvent(ScriptEventType.kNTConnected);
|
ScriptManager.queueEvent(ScriptEventType.kNTConnected);
|
||||||
|
getInstance().broadcastVersion();
|
||||||
|
getInstance().broadcastConnectedStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void broadcastConnectedStatus() {
|
||||||
|
TimedTaskManager.getInstance().addOneShotTask(this::broadcastConnectedStatusImpl, 1000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void broadcastConnectedStatusImpl() {
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
var subMap = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
subMap.put("connected", ntInstance.isConnected());
|
||||||
|
if (ntInstance.isConnected()) {
|
||||||
|
var connections = getInstance().ntInstance.getConnections();
|
||||||
|
if (connections.length > 0) {
|
||||||
|
subMap.put("address", connections[0].remote_ip + ":" + connections[0].remote_port);
|
||||||
|
}
|
||||||
|
subMap.put("clients", connections.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
map.put("ntConnectionInfo", subMap);
|
||||||
|
DataChangeService.getInstance()
|
||||||
|
.publishEvent(new OutgoingUIEvent<>("networkTablesConnected", map));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void broadcastVersion() {
|
||||||
|
kRootTable.getEntry("version").setString(PhotonVersion.versionString);
|
||||||
|
kRootTable.getEntry("buildDate").setString(PhotonVersion.buildDate);
|
||||||
|
}
|
||||||
|
|
||||||
public void setConfig(NetworkConfig config) {
|
public void setConfig(NetworkConfig config) {
|
||||||
if (config.runNTServer) {
|
if (config.runNTServer) {
|
||||||
setServerMode();
|
setServerMode();
|
||||||
} else {
|
} else {
|
||||||
setClientMode(config.teamNumber);
|
setClientMode(config.teamNumber);
|
||||||
}
|
}
|
||||||
|
broadcastVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setClientMode(int teamNumber) {
|
private void setClientMode(int teamNumber) {
|
||||||
@@ -79,17 +113,20 @@ public class NetworkTablesManager {
|
|||||||
ntInstance.stopServer();
|
ntInstance.stopServer();
|
||||||
|
|
||||||
ntInstance.startClientTeam(teamNumber);
|
ntInstance.startClientTeam(teamNumber);
|
||||||
|
ntInstance.startDSClient();
|
||||||
if (ntInstance.isConnected()) {
|
if (ntInstance.isConnected()) {
|
||||||
logger.info("[NetworkTablesManager] Connected to the robot!");
|
logger.info("[NetworkTablesManager] Connected to the robot!");
|
||||||
} else {
|
} else {
|
||||||
logger.error(
|
logger.error(
|
||||||
"[NetworkTablesManager] Could not connect to the robot! Will retry in the background...");
|
"[NetworkTablesManager] Could not connect to the robot! Will retry in the background...");
|
||||||
}
|
}
|
||||||
|
broadcastVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setServerMode() {
|
private void setServerMode() {
|
||||||
logger.info("Starting NT Server");
|
logger.info("Starting NT Server");
|
||||||
ntInstance.stopClient();
|
ntInstance.stopClient();
|
||||||
ntInstance.startServer();
|
ntInstance.startServer();
|
||||||
|
broadcastVersion();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,14 +17,13 @@
|
|||||||
|
|
||||||
package org.photonvision.common.dataflow.websocket;
|
package org.photonvision.common.dataflow.websocket;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import org.photonvision.common.dataflow.CVPipelineResultConsumer;
|
import org.photonvision.common.dataflow.CVPipelineResultConsumer;
|
||||||
|
import org.photonvision.common.dataflow.DataChangeService;
|
||||||
|
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||||
import org.photonvision.common.logging.LogGroup;
|
import org.photonvision.common.logging.LogGroup;
|
||||||
import org.photonvision.common.logging.Logger;
|
import org.photonvision.common.logging.Logger;
|
||||||
import org.photonvision.server.SocketHandler;
|
|
||||||
import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
import org.photonvision.vision.pipeline.result.CVPipelineResult;
|
||||||
|
|
||||||
public class UIDataPublisher implements CVPipelineResultConsumer {
|
public class UIDataPublisher implements CVPipelineResultConsumer {
|
||||||
@@ -39,16 +38,17 @@ public class UIDataPublisher implements CVPipelineResultConsumer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(CVPipelineResult result) {
|
public void accept(CVPipelineResult result) {
|
||||||
var now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
var dataMap = new HashMap<String, Object>();
|
||||||
|
dataMap.put("latency", result.getLatencyMillis());
|
||||||
|
|
||||||
// only update the UI at 15hz
|
// only update the UI at 15hz
|
||||||
if (lastUIResultUpdateTime + 1000.0 / 10.0 > now) return;
|
if (lastUIResultUpdateTime + 1000.0 / 10.0 > now) return;
|
||||||
|
|
||||||
var uiMap = new HashMap<Integer, HashMap<String, Object>>();
|
var uiMap = new HashMap<Integer, HashMap<String, Object>>();
|
||||||
var dataMap = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
dataMap.put("fps", result.fps);
|
dataMap.put("fps", result.fps);
|
||||||
dataMap.put("latency", result.getLatencyMillis());
|
|
||||||
|
|
||||||
var targets = result.targets;
|
var targets = result.targets;
|
||||||
|
|
||||||
@@ -57,18 +57,10 @@ public class UIDataPublisher implements CVPipelineResultConsumer {
|
|||||||
uiTargets.add(t.toHashMap());
|
uiTargets.add(t.toHashMap());
|
||||||
}
|
}
|
||||||
dataMap.put("targets", uiTargets);
|
dataMap.put("targets", uiTargets);
|
||||||
|
|
||||||
uiMap.put(index, dataMap);
|
uiMap.put(index, dataMap);
|
||||||
var retMap = new HashMap<String, Object>();
|
|
||||||
retMap.put("updatePipelineResult", uiMap);
|
|
||||||
|
|
||||||
try {
|
|
||||||
SocketHandler.getInstance().broadcastMessage(retMap, null);
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
logger.error(e.getMessage());
|
|
||||||
logger.error(Arrays.toString(e.getStackTrace()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
DataChangeService.getInstance()
|
||||||
|
.publishEvent(OutgoingUIEvent.wrappedOf("updatePipelineResult", uiMap));
|
||||||
lastUIResultUpdateTime = now;
|
lastUIResultUpdateTime = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,6 @@ import org.photonvision.common.configuration.HardwareConfig;
|
|||||||
import org.photonvision.common.hardware.Platform;
|
import org.photonvision.common.hardware.Platform;
|
||||||
|
|
||||||
public class CustomGPIO extends GPIOBase {
|
public class CustomGPIO extends GPIOBase {
|
||||||
|
|
||||||
private boolean currentState;
|
private boolean currentState;
|
||||||
private final int port;
|
private final int port;
|
||||||
|
|
||||||
@@ -20,14 +20,13 @@ package org.photonvision.common.hardware.GPIO.pi;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that defines the exceptions that can be thrown by Pigpio.
|
* A class that defines the exceptions that can be thrown by Pigpio.
|
||||||
*
|
*
|
||||||
* <p>Credit to nkolban
|
* <p>Credit to nkolban
|
||||||
* https://github.com/nkolban/jpigpio/blob/master/JPigpio/src/jpigpio/PigpioException.java
|
* https://github.com/nkolban/jpigpio/blob/master/JPigpio/src/jpigpio/PigpioException.java
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"SpellCheckingInspection", "unused", "RedundantSuppression"})
|
@SuppressWarnings({"SpellCheckingInspection", "unused", "RedundantSuppression"})
|
||||||
public class PigpioException extends Exception {
|
public class PigpioException extends Exception {
|
||||||
|
|
||||||
private int rc = -99999999;
|
private int rc = -99999999;
|
||||||
private static final long serialVersionUID = 443595760654129068L;
|
private static final long serialVersionUID = 443595760654129068L;
|
||||||
|
|
||||||
@@ -67,10 +66,10 @@ public class PigpioException extends Exception {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the error code that was returned by the underlying Pigpio call.
|
* Retrieve the error code that was returned by the underlying Pigpio call.
|
||||||
*
|
*
|
||||||
* @return The error code that was returned by the underlying Pigpio call.
|
* @return The error code that was returned by the underlying Pigpio call.
|
||||||
*/
|
*/
|
||||||
public int getErrorCode() {
|
public int getErrorCode() {
|
||||||
return rc;
|
return rc;
|
||||||
} // End of getErrorCode
|
} // End of getErrorCode
|
||||||
@@ -24,7 +24,6 @@ import org.photonvision.common.logging.LogGroup;
|
|||||||
import org.photonvision.common.logging.Logger;
|
import org.photonvision.common.logging.Logger;
|
||||||
|
|
||||||
public class PigpioPin extends GPIOBase {
|
public class PigpioPin extends GPIOBase {
|
||||||
|
|
||||||
public static final Logger logger = new Logger(PigpioPin.class, LogGroup.General);
|
public static final Logger logger = new Logger(PigpioPin.class, LogGroup.General);
|
||||||
private static final PigpioSocket piSocket = new PigpioSocket();
|
private static final PigpioSocket piSocket = new PigpioSocket();
|
||||||
|
|
||||||
@@ -23,14 +23,14 @@ public class PigpioPulse {
|
|||||||
int delayMicros;
|
int delayMicros;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises a pulse.
|
* Initialises a pulse.
|
||||||
*
|
*
|
||||||
* @param gpioOn GPIO number to switch on at the start of the pulse. If zero, then no GPIO will be
|
* @param gpioOn GPIO number to switch on at the start of the pulse. If zero, then no GPIO will be
|
||||||
* switched on.
|
* switched on.
|
||||||
* @param gpioOff GPIO number to switch off at the start of the pulse. If zero, then no GPIO will
|
* @param gpioOff GPIO number to switch off at the start of the pulse. If zero, then no GPIO will
|
||||||
* be switched off.
|
* be switched off.
|
||||||
* @param delayMicros the delay in microseconds before the next pulse.
|
* @param delayMicros the delay in microseconds before the next pulse.
|
||||||
*/
|
*/
|
||||||
public PigpioPulse(int gpioOn, int gpioOff, int delayMicros) {
|
public PigpioPulse(int gpioOn, int gpioOff, int delayMicros) {
|
||||||
this.gpioOn = gpioOn != 0 ? 1 << gpioOn : 0;
|
this.gpioOn = gpioOn != 0 ? 1 << gpioOn : 0;
|
||||||
this.gpioOff = gpioOff != 0 ? 1 << gpioOff : 0;
|
this.gpioOff = gpioOff != 0 ? 1 << gpioOff : 0;
|
||||||
@@ -41,12 +41,12 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and starts a socket connection to a pigpio daemon on a remote host with the specified
|
* Creates and starts a socket connection to a pigpio daemon on a remote host with the specified
|
||||||
* address and port
|
* address and port
|
||||||
*
|
*
|
||||||
* @param addr Address of remote pigpio daemon
|
* @param addr Address of remote pigpio daemon
|
||||||
* @param port Port of remote pigpio daemon
|
* @param port Port of remote pigpio daemon
|
||||||
*/
|
*/
|
||||||
public PigpioSocket(String addr, int port) {
|
public PigpioSocket(String addr, int port) {
|
||||||
try {
|
try {
|
||||||
commandSocket = new PigpioSocketLock(addr, port);
|
commandSocket = new PigpioSocketLock(addr, port);
|
||||||
@@ -56,10 +56,10 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconnects to the pigpio daemon
|
* Reconnects to the pigpio daemon
|
||||||
*
|
*
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public void reconnect() throws PigpioException {
|
public void reconnect() throws PigpioException {
|
||||||
try {
|
try {
|
||||||
commandSocket.reconnect();
|
commandSocket.reconnect();
|
||||||
@@ -70,10 +70,10 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminates the connection to the pigpio daemon
|
* Terminates the connection to the pigpio daemon
|
||||||
*
|
*
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public void gpioTerminate() throws PigpioException {
|
public void gpioTerminate() throws PigpioException {
|
||||||
try {
|
try {
|
||||||
commandSocket.terminate();
|
commandSocket.terminate();
|
||||||
@@ -84,12 +84,12 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the GPIO level
|
* Read the GPIO level
|
||||||
*
|
*
|
||||||
* @param pin Pin to read from
|
* @param pin Pin to read from
|
||||||
* @return Value of the pin
|
* @return Value of the pin
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public boolean gpioRead(int pin) throws PigpioException {
|
public boolean gpioRead(int pin) throws PigpioException {
|
||||||
try {
|
try {
|
||||||
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_READ.value, pin);
|
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_READ.value, pin);
|
||||||
@@ -102,12 +102,12 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the GPIO level
|
* Write the GPIO level
|
||||||
*
|
*
|
||||||
* @param pin Pin to write to
|
* @param pin Pin to write to
|
||||||
* @param value Value to write
|
* @param value Value to write
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public void gpioWrite(int pin, boolean value) throws PigpioException {
|
public void gpioWrite(int pin, boolean value) throws PigpioException {
|
||||||
try {
|
try {
|
||||||
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WRITE.value, pin, value ? 1 : 0);
|
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WRITE.value, pin, value ? 1 : 0);
|
||||||
@@ -119,10 +119,10 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all waveforms and any data added by calls to {@link #waveAddGeneric(ArrayList)}
|
* Clears all waveforms and any data added by calls to {@link #waveAddGeneric(ArrayList)}
|
||||||
*
|
*
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public void waveClear() throws PigpioException {
|
public void waveClear() throws PigpioException {
|
||||||
try {
|
try {
|
||||||
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVCLR.value);
|
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVCLR.value);
|
||||||
@@ -134,12 +134,12 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a number of pulses to the current waveform
|
* Adds a number of pulses to the current waveform
|
||||||
*
|
*
|
||||||
* @param pulses ArrayList of pulses to add
|
* @param pulses ArrayList of pulses to add
|
||||||
* @return the new total number of pulses in the current waveform
|
* @return the new total number of pulses in the current waveform
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
private int waveAddGeneric(ArrayList<PigpioPulse> pulses) throws PigpioException {
|
private int waveAddGeneric(ArrayList<PigpioPulse> pulses) throws PigpioException {
|
||||||
// pigpio wave message format
|
// pigpio wave message format
|
||||||
|
|
||||||
@@ -175,12 +175,12 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates pulses and adds them to the current waveform
|
* Creates pulses and adds them to the current waveform
|
||||||
*
|
*
|
||||||
* @param pulseTimeMillis Pulse length in milliseconds
|
* @param pulseTimeMillis Pulse length in milliseconds
|
||||||
* @param blinks Number of times to pulse. -1 for repeat
|
* @param blinks Number of times to pulse. -1 for repeat
|
||||||
* @param pinNo Pin to pulse
|
* @param pinNo Pin to pulse
|
||||||
*/
|
*/
|
||||||
private void addBlinkPulsesToWaveform(int pulseTimeMillis, int blinks, int pinNo) {
|
private void addBlinkPulsesToWaveform(int pulseTimeMillis, int blinks, int pinNo) {
|
||||||
boolean repeat = blinks == -1;
|
boolean repeat = blinks == -1;
|
||||||
|
|
||||||
@@ -208,13 +208,13 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates and sends a waveform to the given pins with the specified parameters.
|
* Generates and sends a waveform to the given pins with the specified parameters.
|
||||||
*
|
*
|
||||||
* @param pulseTimeMillis Pulse length in milliseconds
|
* @param pulseTimeMillis Pulse length in milliseconds
|
||||||
* @param blinks Number of times to pulse. -1 for repeat
|
* @param blinks Number of times to pulse. -1 for repeat
|
||||||
* @param pins Pins to pulse
|
* @param pins Pins to pulse
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public void generateAndSendWaveform(int pulseTimeMillis, int blinks, int... pins)
|
public void generateAndSendWaveform(int pulseTimeMillis, int blinks, int... pins)
|
||||||
throws PigpioException {
|
throws PigpioException {
|
||||||
if (pins.length == 0) return;
|
if (pins.length == 0) return;
|
||||||
@@ -263,11 +263,11 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the transmission of the current waveform
|
* Stops the transmission of the current waveform
|
||||||
*
|
*
|
||||||
* @return success
|
* @return success
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public boolean waveTxStop() throws PigpioException {
|
public boolean waveTxStop() throws PigpioException {
|
||||||
try {
|
try {
|
||||||
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVHLT.value);
|
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVHLT.value);
|
||||||
@@ -280,12 +280,12 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a waveform from the data provided by the prior calls to {@link
|
* Creates a waveform from the data provided by the prior calls to {@link
|
||||||
* #waveAddGeneric(ArrayList)} Upon success a wave ID greater than or equal to 0 is returned
|
* #waveAddGeneric(ArrayList)} Upon success a wave ID greater than or equal to 0 is returned
|
||||||
*
|
*
|
||||||
* @return ID of the created waveform
|
* @return ID of the created waveform
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public int waveCreate() throws PigpioException {
|
public int waveCreate() throws PigpioException {
|
||||||
try {
|
try {
|
||||||
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVCRE.value);
|
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVCRE.value);
|
||||||
@@ -298,11 +298,11 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the waveform with specified wave ID
|
* Deletes the waveform with specified wave ID
|
||||||
*
|
*
|
||||||
* @param waveId ID of the waveform to delete
|
* @param waveId ID of the waveform to delete
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public void waveDelete(int waveId) throws PigpioException {
|
public void waveDelete(int waveId) throws PigpioException {
|
||||||
try {
|
try {
|
||||||
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVDEL.value, waveId);
|
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVDEL.value, waveId);
|
||||||
@@ -314,12 +314,12 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transmits the waveform with specified wave ID. The waveform is sent once
|
* Transmits the waveform with specified wave ID. The waveform is sent once
|
||||||
*
|
*
|
||||||
* @param waveId ID of the waveform to transmit
|
* @param waveId ID of the waveform to transmit
|
||||||
* @return The number of DMA control blocks in the waveform
|
* @return The number of DMA control blocks in the waveform
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public int waveSendOnce(int waveId) throws PigpioException {
|
public int waveSendOnce(int waveId) throws PigpioException {
|
||||||
try {
|
try {
|
||||||
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVTX.value, waveId);
|
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVTX.value, waveId);
|
||||||
@@ -331,13 +331,13 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transmits the waveform with specified wave ID. The waveform cycles until cancelled (either by
|
* Transmits the waveform with specified wave ID. The waveform cycles until cancelled (either by
|
||||||
* the sending of a new waveform or {@link #waveTxStop()}
|
* the sending of a new waveform or {@link #waveTxStop()}
|
||||||
*
|
*
|
||||||
* @param waveId ID of the waveform to transmit
|
* @param waveId ID of the waveform to transmit
|
||||||
* @return The number of DMA control blocks in the waveform
|
* @return The number of DMA control blocks in the waveform
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public int waveSendRepeat(int waveId) throws PigpioException {
|
public int waveSendRepeat(int waveId) throws PigpioException {
|
||||||
try {
|
try {
|
||||||
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVTXR.value, waveId);
|
int retCode = commandSocket.sendCmd(PigpioCommand.PCMD_WVTXR.value, waveId);
|
||||||
@@ -349,14 +349,14 @@ public class PigpioSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts hardware PWM on a GPIO at the specified frequency and dutycycle
|
* Starts hardware PWM on a GPIO at the specified frequency and dutycycle
|
||||||
*
|
*
|
||||||
* @param pin GPIO pin to start PWM on
|
* @param pin GPIO pin to start PWM on
|
||||||
* @param pwmFrequency Frequency to run at (1Hz-125MHz). Frequencies above 30MHz are unlikely to
|
* @param pwmFrequency Frequency to run at (1Hz-125MHz). Frequencies above 30MHz are unlikely to
|
||||||
* work
|
* work
|
||||||
* @param pwmDuty Duty cycle to run at (0-1,000,000)
|
* @param pwmDuty Duty cycle to run at (0-1,000,000)
|
||||||
* @throws PigpioException on failure
|
* @throws PigpioException on failure
|
||||||
*/
|
*/
|
||||||
public void hardwarePWM(int pin, int pwmFrequency, int pwmDuty) throws PigpioException {
|
public void hardwarePWM(int pin, int pwmFrequency, int pwmDuty) throws PigpioException {
|
||||||
try {
|
try {
|
||||||
ByteBuffer bb = ByteBuffer.allocate(4);
|
ByteBuffer bb = ByteBuffer.allocate(4);
|
||||||
@@ -24,9 +24,9 @@ import java.net.Socket;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Credit to nkolban
|
* Credit to nkolban
|
||||||
* https://github.com/nkolban/jpigpio/blob/master/JPigpio/src/jpigpio/SocketLock.java
|
* https://github.com/nkolban/jpigpio/blob/master/JPigpio/src/jpigpio/SocketLock.java
|
||||||
*/
|
*/
|
||||||
final class PigpioSocketLock {
|
final class PigpioSocketLock {
|
||||||
private static final int replyTimeoutMillis = 1000;
|
private static final int replyTimeoutMillis = 1000;
|
||||||
|
|
||||||
@@ -82,16 +82,16 @@ final class PigpioSocketLock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send extended command to pigpiod and return result code
|
* Send extended command to pigpiod and return result code
|
||||||
*
|
*
|
||||||
* @param cmd Command to send
|
* @param cmd Command to send
|
||||||
* @param p1 Command parameter 1
|
* @param p1 Command parameter 1
|
||||||
* @param p2 Command parameter 2
|
* @param p2 Command parameter 2
|
||||||
* @param p3 Command parameter 3 (usually length of extended data - see paramater ext)
|
* @param p3 Command parameter 3 (usually length of extended data - see paramater ext)
|
||||||
* @param ext Array of bytes containing extended data
|
* @param ext Array of bytes containing extended data
|
||||||
* @return Command result code
|
* @return Command result code
|
||||||
* @throws IOException in case of network connection error
|
* @throws IOException in case of network connection error
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("UnusedAssignment")
|
@SuppressWarnings("UnusedAssignment")
|
||||||
public synchronized int sendCmd(int cmd, int p1, int p2, int p3, byte[] ext) throws IOException {
|
public synchronized int sendCmd(int cmd, int p1, int p2, int p3, byte[] ext) throws IOException {
|
||||||
ByteBuffer bb = ByteBuffer.allocate(16 + ext.length);
|
ByteBuffer bb = ByteBuffer.allocate(16 + ext.length);
|
||||||
@@ -136,11 +136,11 @@ final class PigpioSocketLock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read all remaining bytes coming from pigpiod
|
* Read all remaining bytes coming from pigpiod
|
||||||
*
|
*
|
||||||
* @param data Array to store read bytes.
|
* @param data Array to store read bytes.
|
||||||
* @throws IOException if unable to read from network
|
* @throws IOException if unable to read from network
|
||||||
*/
|
*/
|
||||||
public void readBytes(byte[] data) throws IOException {
|
public void readBytes(byte[] data) throws IOException {
|
||||||
in.readFully(data);
|
in.readFully(data);
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,6 @@ import org.photonvision.common.dataflow.networktables.NTDataChangeListener;
|
|||||||
import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
|
import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
|
||||||
import org.photonvision.common.hardware.GPIO.CustomGPIO;
|
import org.photonvision.common.hardware.GPIO.CustomGPIO;
|
||||||
import org.photonvision.common.hardware.GPIO.pi.PigpioSocket;
|
import org.photonvision.common.hardware.GPIO.pi.PigpioSocket;
|
||||||
import org.photonvision.common.hardware.VisionLED.VisionLEDMode;
|
|
||||||
import org.photonvision.common.hardware.metrics.MetricsBase;
|
import org.photonvision.common.hardware.metrics.MetricsBase;
|
||||||
import org.photonvision.common.logging.LogGroup;
|
import org.photonvision.common.logging.LogGroup;
|
||||||
import org.photonvision.common.logging.Logger;
|
import org.photonvision.common.logging.Logger;
|
||||||
@@ -91,7 +90,7 @@ public class HardwareManager {
|
|||||||
pigpioSocket);
|
pigpioSocket);
|
||||||
|
|
||||||
ledModeEntry = NetworkTablesManager.getInstance().kRootTable.getEntry("ledMode");
|
ledModeEntry = NetworkTablesManager.getInstance().kRootTable.getEntry("ledMode");
|
||||||
ledModeEntry.setNumber(VisionLEDMode.VLM_DEFAULT.value);
|
ledModeEntry.setNumber(VisionLEDMode.kDefault.value);
|
||||||
ledModeListener =
|
ledModeListener =
|
||||||
visionLED == null
|
visionLED == null
|
||||||
? null
|
? null
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Photon Vision.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.photonvision.common.hardware;
|
||||||
|
|
||||||
|
public enum PiVersion {
|
||||||
|
PI_B("Pi Model B"),
|
||||||
|
COMPUTE_MODULE("Compute Module Rev"),
|
||||||
|
ZERO_W("Pi Zero W Rev 1.1"),
|
||||||
|
ZERO_2_W("Raspberry Pi Zero 2"),
|
||||||
|
PI_3("Pi 3"),
|
||||||
|
PI_4("Pi 4"),
|
||||||
|
COMPUTE_MODULE_3("Compute Module 3"),
|
||||||
|
UNKNOWN("UNKNOWN");
|
||||||
|
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
PiVersion(String s) {
|
||||||
|
this.identifier = s.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PiVersion getPiVersion() {
|
||||||
|
if (!Platform.isRaspberryPi()) return PiVersion.UNKNOWN;
|
||||||
|
String piString = Platform.currentPiVersionStr;
|
||||||
|
for (PiVersion p : PiVersion.values()) {
|
||||||
|
if (piString.toLowerCase().contains(p.identifier)) return p;
|
||||||
|
}
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package org.photonvision.common.hardware;
|
package org.photonvision.common.hardware;
|
||||||
|
|
||||||
import edu.wpi.first.wpiutil.RuntimeDetector;
|
import edu.wpi.first.util.RuntimeDetector;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.photonvision.common.util.ShellExec;
|
import org.photonvision.common.util.ShellExec;
|
||||||
|
|
||||||
@@ -46,7 +46,11 @@ public enum Platform {
|
|||||||
|
|
||||||
private static final String OS_NAME = System.getProperty("os.name");
|
private static final String OS_NAME = System.getProperty("os.name");
|
||||||
private static final String OS_ARCH = System.getProperty("os.arch");
|
private static final String OS_ARCH = System.getProperty("os.arch");
|
||||||
public static final Platform CurrentPlatform = getCurrentPlatform();
|
|
||||||
|
// These are queried on init and should never change after
|
||||||
|
public static final Platform currentPlatform = getCurrentPlatform();
|
||||||
|
protected static final String currentPiVersionStr = getPiVersionString();
|
||||||
|
public static final PiVersion currentPiVersion = PiVersion.getPiVersion();
|
||||||
|
|
||||||
private static String UnknownPlatformString =
|
private static String UnknownPlatformString =
|
||||||
String.format("Unknown Platform. OS: %s, Architecture: %s", OS_NAME, OS_ARCH);
|
String.format("Unknown Platform. OS: %s, Architecture: %s", OS_NAME, OS_ARCH);
|
||||||
@@ -62,7 +66,7 @@ public enum Platform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isRaspberryPi() {
|
public static boolean isRaspberryPi() {
|
||||||
return CurrentPlatform.equals(LINUX_RASPBIAN);
|
return currentPlatform.equals(LINUX_RASPBIAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("StatementWithEmptyBody")
|
@SuppressWarnings("StatementWithEmptyBody")
|
||||||
@@ -115,4 +119,22 @@ public enum Platform {
|
|||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Querry /proc/device-tree/model. This should return the model of the pi
|
||||||
|
// Versions here:
|
||||||
|
// https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/bcm2710-rpi-cm3.dts
|
||||||
|
private static String getPiVersionString() {
|
||||||
|
if (!isRaspberryPi()) return "";
|
||||||
|
try {
|
||||||
|
shell.executeBashCommand("cat /proc/device-tree/model");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (shell.getExitCode() == 0) {
|
||||||
|
// We expect it to be in the format "raspberry pi X model X"
|
||||||
|
return shell.getOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ public class VisionLED {
|
|||||||
private final int brightnessMax;
|
private final int brightnessMax;
|
||||||
private final PigpioSocket pigpioSocket;
|
private final PigpioSocket pigpioSocket;
|
||||||
|
|
||||||
private VisionLEDMode currentLedMode = VisionLEDMode.VLM_DEFAULT;
|
private VisionLEDMode currentLedMode = VisionLEDMode.kDefault;
|
||||||
private BooleanSupplier pipelineModeSupplier;
|
private BooleanSupplier pipelineModeSupplier;
|
||||||
|
|
||||||
private int mappedBrightnessPercentage;
|
private int mappedBrightnessPercentage;
|
||||||
@@ -111,7 +111,7 @@ public class VisionLED {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setState(boolean on) {
|
public void setState(boolean on) {
|
||||||
setInternal(on ? VisionLEDMode.VLM_ON : VisionLEDMode.VLM_OFF, false);
|
setInternal(on ? VisionLEDMode.kOn : VisionLEDMode.kOff, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onLedModeChange(EntryNotification entryNotification) {
|
void onLedModeChange(EntryNotification entryNotification) {
|
||||||
@@ -120,20 +120,20 @@ public class VisionLED {
|
|||||||
VisionLEDMode newLedMode;
|
VisionLEDMode newLedMode;
|
||||||
switch (newLedModeRaw) {
|
switch (newLedModeRaw) {
|
||||||
case -1:
|
case -1:
|
||||||
newLedMode = VisionLEDMode.VLM_DEFAULT;
|
newLedMode = VisionLEDMode.kDefault;
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
newLedMode = VisionLEDMode.VLM_OFF;
|
newLedMode = VisionLEDMode.kOff;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
newLedMode = VisionLEDMode.VLM_ON;
|
newLedMode = VisionLEDMode.kOn;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
newLedMode = VisionLEDMode.VLM_BLINK;
|
newLedMode = VisionLEDMode.kBlink;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger.warn("User supplied invalid LED mode, falling back to Default");
|
logger.warn("User supplied invalid LED mode, falling back to Default");
|
||||||
newLedMode = VisionLEDMode.VLM_DEFAULT;
|
newLedMode = VisionLEDMode.kDefault;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
setInternal(newLedMode, true);
|
setInternal(newLedMode, true);
|
||||||
@@ -145,16 +145,16 @@ public class VisionLED {
|
|||||||
|
|
||||||
if (fromNT) {
|
if (fromNT) {
|
||||||
switch (newLedMode) {
|
switch (newLedMode) {
|
||||||
case VLM_DEFAULT:
|
case kDefault:
|
||||||
setStateImpl(pipelineModeSupplier.getAsBoolean());
|
setStateImpl(pipelineModeSupplier.getAsBoolean());
|
||||||
break;
|
break;
|
||||||
case VLM_OFF:
|
case kOff:
|
||||||
setStateImpl(false);
|
setStateImpl(false);
|
||||||
break;
|
break;
|
||||||
case VLM_ON:
|
case kOn:
|
||||||
setStateImpl(true);
|
setStateImpl(true);
|
||||||
break;
|
break;
|
||||||
case VLM_BLINK:
|
case kBlink:
|
||||||
blinkImpl(85, -1);
|
blinkImpl(85, -1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -166,15 +166,15 @@ public class VisionLED {
|
|||||||
+ newLedMode.toString()
|
+ newLedMode.toString()
|
||||||
+ "\"");
|
+ "\"");
|
||||||
} else {
|
} else {
|
||||||
if (currentLedMode == VisionLEDMode.VLM_DEFAULT) {
|
if (currentLedMode == VisionLEDMode.kDefault) {
|
||||||
switch (newLedMode) {
|
switch (newLedMode) {
|
||||||
case VLM_DEFAULT:
|
case kDefault:
|
||||||
setStateImpl(pipelineModeSupplier.getAsBoolean());
|
setStateImpl(pipelineModeSupplier.getAsBoolean());
|
||||||
break;
|
break;
|
||||||
case VLM_OFF:
|
case kOff:
|
||||||
setStateImpl(false);
|
setStateImpl(false);
|
||||||
break;
|
break;
|
||||||
case VLM_ON:
|
case kOn:
|
||||||
setStateImpl(true);
|
setStateImpl(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -182,32 +182,4 @@ public class VisionLED {
|
|||||||
logger.info("Changing LED internal state to " + newLedMode.toString());
|
logger.info("Changing LED internal state to " + newLedMode.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum VisionLEDMode {
|
|
||||||
VLM_DEFAULT(-1),
|
|
||||||
VLM_OFF(0),
|
|
||||||
VLM_ON(1),
|
|
||||||
VLM_BLINK(2);
|
|
||||||
|
|
||||||
public final int value;
|
|
||||||
|
|
||||||
VisionLEDMode(int value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
switch (this) {
|
|
||||||
case VLM_DEFAULT:
|
|
||||||
return "Default";
|
|
||||||
case VLM_OFF:
|
|
||||||
return "Off";
|
|
||||||
case VLM_ON:
|
|
||||||
return "On";
|
|
||||||
case VLM_BLINK:
|
|
||||||
return "Blink";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.photonvision.common.hardware.metrics;
|
package org.photonvision.common.hardware.metrics;
|
||||||
|
|
||||||
public class CPUMetrics extends MetricsBase {
|
public class CPUMetrics extends MetricsBase {
|
||||||
|
|
||||||
private String cpuMemSplit = null;
|
private String cpuMemSplit = null;
|
||||||
|
|
||||||
public String getMemory() {
|
public String getMemory() {
|
||||||
@@ -17,13 +17,13 @@
|
|||||||
|
|
||||||
package org.photonvision.common.hardware.metrics;
|
package org.photonvision.common.hardware.metrics;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import org.photonvision.common.dataflow.DataChangeService;
|
||||||
|
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||||
import org.photonvision.common.hardware.Platform;
|
import org.photonvision.common.hardware.Platform;
|
||||||
import org.photonvision.common.logging.LogGroup;
|
import org.photonvision.common.logging.LogGroup;
|
||||||
import org.photonvision.common.logging.Logger;
|
import org.photonvision.common.logging.Logger;
|
||||||
import org.photonvision.common.util.TimedTaskManager;
|
import org.photonvision.common.util.TimedTaskManager;
|
||||||
import org.photonvision.server.SocketHandler;
|
|
||||||
|
|
||||||
public class MetricsPublisher {
|
public class MetricsPublisher {
|
||||||
private static final Logger logger = new Logger(MetricsPublisher.class, LogGroup.General);
|
private static final Logger logger = new Logger(MetricsPublisher.class, LogGroup.General);
|
||||||
@@ -65,14 +65,7 @@ public class MetricsPublisher {
|
|||||||
metrics.put("gpuMemUtil", gpuMetrics.getMallocedMemory());
|
metrics.put("gpuMemUtil", gpuMetrics.getMallocedMemory());
|
||||||
metrics.put("diskUtilPct", diskMetrics.getUsedDiskPct());
|
metrics.put("diskUtilPct", diskMetrics.getUsedDiskPct());
|
||||||
|
|
||||||
var retMap = new HashMap<String, Object>();
|
DataChangeService.getInstance().publishEvent(OutgoingUIEvent.wrappedOf("metrics", metrics));
|
||||||
retMap.put("metrics", metrics);
|
|
||||||
|
|
||||||
try {
|
|
||||||
SocketHandler.getInstance().broadcastMessage(retMap, null);
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
logger.error("Exception while sending metrics!", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Singleton {
|
private static class Singleton {
|
||||||
@@ -33,11 +33,9 @@ import org.photonvision.common.configuration.ConfigManager;
|
|||||||
import org.photonvision.common.dataflow.DataChangeService;
|
import org.photonvision.common.dataflow.DataChangeService;
|
||||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||||
import org.photonvision.common.util.TimedTaskManager;
|
import org.photonvision.common.util.TimedTaskManager;
|
||||||
import org.photonvision.server.SocketHandler;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class Logger {
|
public class Logger {
|
||||||
|
|
||||||
public static final String ANSI_RESET = "\u001B[0m";
|
public static final String ANSI_RESET = "\u001B[0m";
|
||||||
public static final String ANSI_BLACK = "\u001B[30m";
|
public static final String ANSI_BLACK = "\u001B[30m";
|
||||||
public static final String ANSI_RED = "\u001B[31m";
|
public static final String ANSI_RED = "\u001B[31m";
|
||||||
@@ -128,9 +126,9 @@ public class Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void cleanLogs(Path folderToClean) {
|
public static void cleanLogs(Path folderToClean) {
|
||||||
|
File[] logs = folderToClean.toFile().listFiles();
|
||||||
LinkedList<File> logFileList =
|
if (logs == null) return;
|
||||||
new LinkedList<>(Arrays.asList(folderToClean.toFile().listFiles()));
|
LinkedList<File> logFileList = new LinkedList<>(Arrays.asList(logs));
|
||||||
HashMap<File, Date> logFileStartDateMap = new HashMap<>();
|
HashMap<File, Date> logFileStartDateMap = new HashMap<>();
|
||||||
|
|
||||||
// Remove any files from the list for which we can't parse a start date from their name.
|
// Remove any files from the list for which we can't parse a start date from their name.
|
||||||
@@ -235,12 +233,12 @@ public class Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs an error message with the stack trace of a Throwable. The stacktrace will only be printed
|
* Logs an error message with the stack trace of a Throwable. The stacktrace will only be printed
|
||||||
* if the current LogLevel is TRACE
|
* if the current LogLevel is TRACE
|
||||||
*
|
*
|
||||||
* @param message
|
* @param message
|
||||||
* @param t
|
* @param t
|
||||||
*/
|
*/
|
||||||
public void error(String message, Throwable t) {
|
public void error(String message, Throwable t) {
|
||||||
log(message, LogLevel.ERROR);
|
log(message, LogLevel.ERROR);
|
||||||
log(convertStackTraceToString(t), LogLevel.ERROR, LogLevel.DEBUG);
|
log(convertStackTraceToString(t), LogLevel.ERROR, LogLevel.DEBUG);
|
||||||
@@ -302,12 +300,12 @@ public class Logger {
|
|||||||
private static class UILogAppender implements LogAppender {
|
private static class UILogAppender implements LogAppender {
|
||||||
@Override
|
@Override
|
||||||
public void log(String message, LogLevel level) {
|
public void log(String message, LogLevel level) {
|
||||||
var messageMap = new SocketHandler.UIMap();
|
var messageMap = new HashMap<String, Object>();
|
||||||
messageMap.put("logMessage", message);
|
messageMap.put("logMessage", message);
|
||||||
messageMap.put("logLevel", level.code);
|
messageMap.put("logLevel", level.code);
|
||||||
var superMap = new SocketHandler.UIMap();
|
var superMap = new HashMap<String, Object>();
|
||||||
superMap.put("logMessage", messageMap);
|
superMap.put("logMessage", messageMap);
|
||||||
DataChangeService.getInstance().publishEvent(new OutgoingUIEvent<>("log", superMap));
|
DataChangeService.getInstance().publishEvent(OutgoingUIEvent.wrappedOf("log", superMap));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,6 +343,8 @@ public class Logger {
|
|||||||
wantsFlush = true;
|
wantsFlush = true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// Nothing to do - no stream available for writing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,6 @@ import org.photonvision.common.logging.Logger;
|
|||||||
import org.photonvision.common.util.ShellExec;
|
import org.photonvision.common.util.ShellExec;
|
||||||
|
|
||||||
public class NetworkManager {
|
public class NetworkManager {
|
||||||
|
|
||||||
private static final Logger logger = new Logger(NetworkManager.class, LogGroup.General);
|
private static final Logger logger = new Logger(NetworkManager.class, LogGroup.General);
|
||||||
|
|
||||||
private NetworkManager() {}
|
private NetworkManager() {}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Photon Vision.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.photonvision.common.networking;
|
||||||
|
|
||||||
|
import edu.wpi.first.cscore.CameraServerJNI;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import org.photonvision.common.dataflow.DataChangeService;
|
||||||
|
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||||
|
import org.photonvision.common.logging.LogGroup;
|
||||||
|
import org.photonvision.common.logging.Logger;
|
||||||
|
|
||||||
|
public class RoborioFinder {
|
||||||
|
private static RoborioFinder instance;
|
||||||
|
private static final Logger logger = new Logger(RoborioFinder.class, LogGroup.General);
|
||||||
|
|
||||||
|
public static RoborioFinder getInstance() {
|
||||||
|
if (instance == null) instance = new RoborioFinder();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void findRios() {
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
var subMap = new HashMap<String, Object>();
|
||||||
|
// Seperate from the above so we don't hold stuff up
|
||||||
|
System.setProperty("java.net.preferIPv4Stack", "true");
|
||||||
|
subMap.put(
|
||||||
|
"deviceips",
|
||||||
|
Arrays.stream(CameraServerJNI.getNetworkInterfaces())
|
||||||
|
.filter(it -> !it.equals("0.0.0.0"))
|
||||||
|
.toArray());
|
||||||
|
logger.info("Searching for rios");
|
||||||
|
List<String> possibleRioList = new ArrayList<>();
|
||||||
|
for (var ip : CameraServerJNI.getNetworkInterfaces()) {
|
||||||
|
logger.info("Trying " + ip);
|
||||||
|
var possibleRioAddr = getPossibleRioAddress(ip);
|
||||||
|
if (possibleRioAddr != null) {
|
||||||
|
logger.info("Maybe found " + ip);
|
||||||
|
searchForHost(possibleRioList, possibleRioAddr);
|
||||||
|
} else {
|
||||||
|
logger.info("Didn't match RIO IP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String name =
|
||||||
|
// "roboRIO-"
|
||||||
|
// +
|
||||||
|
// ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||||
|
// + "-FRC.local";
|
||||||
|
// searchForHost(possibleRioList, name);
|
||||||
|
// name =
|
||||||
|
// "roboRIO-"
|
||||||
|
// +
|
||||||
|
// ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||||
|
// + "-FRC.lan";
|
||||||
|
// searchForHost(possibleRioList, name);
|
||||||
|
// name =
|
||||||
|
// "roboRIO-"
|
||||||
|
// +
|
||||||
|
// ConfigManager.getInstance().getConfig().getNetworkConfig().teamNumber
|
||||||
|
// + "-FRC.frc-field.local";
|
||||||
|
// searchForHost(possibleRioList, name);
|
||||||
|
// subMap.put("possibleRios", possibleRioList.toArray());
|
||||||
|
|
||||||
|
subMap.put("possibleRios", possibleRioList.toArray());
|
||||||
|
map.put("networkInfo", subMap);
|
||||||
|
DataChangeService.getInstance().publishEvent(new OutgoingUIEvent<>("deviceIpInfo", map));
|
||||||
|
}
|
||||||
|
|
||||||
|
String getPossibleRioAddress(String ip) {
|
||||||
|
try {
|
||||||
|
InetAddress addr = InetAddress.getByName(ip);
|
||||||
|
var address = addr.getAddress();
|
||||||
|
if (address[0] != (byte) (10 & 0xff)) return null;
|
||||||
|
address[3] = (byte) (2 & 0xff);
|
||||||
|
return InetAddress.getByAddress(address).getHostAddress();
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void searchForHost(List<String> list, String hostname) {
|
||||||
|
try {
|
||||||
|
logger.info("Looking up " + hostname);
|
||||||
|
InetAddress testAddr = InetAddress.getByName(hostname);
|
||||||
|
logger.info("Pinging " + hostname);
|
||||||
|
var canContact = testAddr.isReachable(500);
|
||||||
|
if (canContact) {
|
||||||
|
logger.info("Was able to connect to " + hostname);
|
||||||
|
if (!list.contains(hostname)) list.add(hostname);
|
||||||
|
} else {
|
||||||
|
logger.info("Unable to reach " + hostname);
|
||||||
|
}
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,6 @@ import org.photonvision.common.util.TimedTaskManager;
|
|||||||
import org.photonvision.common.util.file.JacksonUtils;
|
import org.photonvision.common.util.file.JacksonUtils;
|
||||||
|
|
||||||
public class ScriptManager {
|
public class ScriptManager {
|
||||||
|
|
||||||
private static final Logger logger = new Logger(ScriptManager.class, LogGroup.General);
|
private static final Logger logger = new Logger(ScriptManager.class, LogGroup.General);
|
||||||
|
|
||||||
private ScriptManager() {}
|
private ScriptManager() {}
|
||||||
@@ -67,8 +66,7 @@ public class ScriptManager {
|
|||||||
|
|
||||||
private void handleEvent(ScriptEventType eventType) {
|
private void handleEvent(ScriptEventType eventType) {
|
||||||
var toRun =
|
var toRun =
|
||||||
events
|
events.parallelStream()
|
||||||
.parallelStream()
|
|
||||||
.filter(e -> e.config.eventType == eventType)
|
.filter(e -> e.config.eventType == eventType)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
@@ -83,7 +81,6 @@ public class ScriptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static class ScriptConfigManager {
|
protected static class ScriptConfigManager {
|
||||||
|
|
||||||
// protected static final Path scriptConfigPath =
|
// protected static final Path scriptConfigPath =
|
||||||
// Paths.get(ConfigManager.SettingsPath.toString(), "scripts.json");
|
// Paths.get(ConfigManager.SettingsPath.toString(), "scripts.json");
|
||||||
static final Path scriptConfigPath = Paths.get(""); // TODO: Waiting on config
|
static final Path scriptConfigPath = Paths.get(""); // TODO: Waiting on config
|
||||||
@@ -131,7 +128,7 @@ public class ScriptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void queueEvent(ScriptEventType eventType) {
|
public static void queueEvent(ScriptEventType eventType) {
|
||||||
if (!Platform.CurrentPlatform.isWindows()) {
|
if (!Platform.currentPlatform.isWindows()) {
|
||||||
try {
|
try {
|
||||||
queuedEvents.putLast(eventType);
|
queuedEvents.putLast(eventType);
|
||||||
logger.info("Queued event: " + eventType.name());
|
logger.info("Queued event: " + eventType.name());
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.photonvision.common.util;
|
package org.photonvision.common.util;
|
||||||
|
|
||||||
public class MemoryManager {
|
public class MemoryManager {
|
||||||
|
|
||||||
private static final long MEGABYTE_FACTOR = 1024L * 1024L;
|
private static final long MEGABYTE_FACTOR = 1024L * 1024L;
|
||||||
|
|
||||||
private int collectionThreshold;
|
private int collectionThreshold;
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
package org.photonvision.common.util;
|
package org.photonvision.common.util;
|
||||||
|
|
||||||
public class ReflectionUtils {
|
public class ReflectionUtils {
|
||||||
|
|
||||||
public static StackTraceElement[] getFullStackTrace() {
|
public static StackTraceElement[] getFullStackTrace() {
|
||||||
return Thread.currentThread().getStackTrace();
|
return Thread.currentThread().getStackTrace();
|
||||||
}
|
}
|
||||||
@@ -44,12 +44,12 @@ public class ShellExec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a bash command. We can handle complex bash commands including multiple executions (; |
|
* Execute a bash command. We can handle complex bash commands including multiple executions (; |
|
||||||
* and ||), quotes, expansions ($), escapes (\), e.g.: "cd /abc/def; mv ghi 'older ghi '$(whoami)"
|
* and ||), quotes, expansions ($), escapes (\), e.g.: "cd /abc/def; mv ghi 'older ghi '$(whoami)"
|
||||||
*
|
*
|
||||||
* @param command Bash command to execute
|
* @param command Bash command to execute
|
||||||
* @return true if bash got started, but your command may have failed.
|
* @return true if bash got started, but your command may have failed.
|
||||||
*/
|
*/
|
||||||
public int executeBashCommand(String command, boolean wait) throws IOException {
|
public int executeBashCommand(String command, boolean wait) throws IOException {
|
||||||
logger.debug("Executing \"" + command + "\"");
|
logger.debug("Executing \"" + command + "\"");
|
||||||
|
|
||||||
@@ -72,25 +72,25 @@ public class ShellExec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a command in current folder, and wait for process to end
|
* Execute a command in current folder, and wait for process to end
|
||||||
*
|
*
|
||||||
* @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")
|
* @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")
|
||||||
* @param args 0..n command line arguments
|
* @param args 0..n command line arguments
|
||||||
* @return process exit code
|
* @return process exit code
|
||||||
*/
|
*/
|
||||||
public int execute(String command, String... args) throws IOException {
|
public int execute(String command, String... args) throws IOException {
|
||||||
return execute(command, null, true, args);
|
return execute(command, null, true, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a command.
|
* Execute a command.
|
||||||
*
|
*
|
||||||
* @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")
|
* @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")
|
||||||
* @param workdir working directory or NULL to use command folder
|
* @param workdir working directory or NULL to use command folder
|
||||||
* @param wait wait for process to end
|
* @param wait wait for process to end
|
||||||
* @param args 0..n command line arguments
|
* @param args 0..n command line arguments
|
||||||
* @return process exit code
|
* @return process exit code
|
||||||
*/
|
*/
|
||||||
public int execute(String command, String workdir, boolean wait, String... args)
|
public int execute(String command, String workdir, boolean wait, String... args)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String[] cmdArr;
|
String[] cmdArr;
|
||||||
@@ -154,10 +154,10 @@ public class ShellExec {
|
|||||||
// ********************************************
|
// ********************************************
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StreamGobbler reads inputstream to "gobble" it. This is used by Executor class when running a
|
* StreamGobbler reads inputstream to "gobble" it. This is used by Executor class when running a
|
||||||
* commandline applications. Gobblers must read/purge INSTR and ERRSTR process streams.
|
* commandline applications. Gobblers must read/purge INSTR and ERRSTR process streams.
|
||||||
* http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
|
* http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
private static class StreamGobbler extends Thread {
|
private static class StreamGobbler extends Thread {
|
||||||
private InputStream is;
|
private InputStream is;
|
||||||
@@ -187,19 +187,19 @@ public class ShellExec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get inputstream buffer or null if stream was not consumed.
|
* Get inputstream buffer or null if stream was not consumed.
|
||||||
*
|
*
|
||||||
* @return Output stream
|
* @return Output stream
|
||||||
*/
|
*/
|
||||||
public String getOutput() {
|
public String getOutput() {
|
||||||
return (output != null ? output.toString() : null);
|
return (output != null ? output.toString() : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is input stream completed.
|
* Is input stream completed.
|
||||||
*
|
*
|
||||||
* @return if input stream is completed
|
* @return if input stream is completed
|
||||||
*/
|
*/
|
||||||
public boolean isCompleted() {
|
public boolean isCompleted() {
|
||||||
return completed;
|
return completed;
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,8 @@
|
|||||||
package org.photonvision.common.util;
|
package org.photonvision.common.util;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import edu.wpi.cscore.CameraServerCvJNI;
|
import edu.wpi.first.cscore.CameraServerCvJNI;
|
||||||
|
import edu.wpi.first.math.util.Units;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -28,7 +29,6 @@ import org.opencv.highgui.HighGui;
|
|||||||
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
|
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
|
||||||
|
|
||||||
public class TestUtils {
|
public class TestUtils {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public enum WPI2019Image {
|
public enum WPI2019Image {
|
||||||
kCargoAngledDark48in(1.2192),
|
kCargoAngledDark48in(1.2192),
|
||||||
@@ -99,6 +99,26 @@ public class TestUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum WPI2022Image {
|
||||||
|
kTerminal12ft6in(Units.feetToMeters(12.5)),
|
||||||
|
kTerminal22ft6in(Units.feetToMeters(22.5));
|
||||||
|
|
||||||
|
public static double FOV = 68.5;
|
||||||
|
|
||||||
|
public final double distanceMeters;
|
||||||
|
public final Path path;
|
||||||
|
|
||||||
|
Path getPath() {
|
||||||
|
var filename = this.toString().substring(1).replace('_', '-');
|
||||||
|
return Path.of("2022", "WPI", filename + ".png");
|
||||||
|
}
|
||||||
|
|
||||||
|
WPI2022Image(double distanceMeters) {
|
||||||
|
this.distanceMeters = distanceMeters;
|
||||||
|
this.path = getPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum PolygonTestImages {
|
public enum PolygonTestImages {
|
||||||
kPolygons;
|
kPolygons;
|
||||||
|
|
||||||
@@ -135,7 +155,8 @@ public class TestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Path getResourcesFolderPath(boolean testMode) {
|
private static Path getResourcesFolderPath(boolean testMode) {
|
||||||
return Path.of("src", (testMode ? "main" : "test"), "resources").toAbsolutePath();
|
System.out.println("CWD: " + Path.of("").toAbsolutePath().toString());
|
||||||
|
return Path.of("test-resources").toAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Path getTestMode2019ImagePath() {
|
public static Path getTestMode2019ImagePath() {
|
||||||
@@ -150,6 +171,12 @@ public class TestUtils {
|
|||||||
.resolve(WPI2020Image.kBlueGoal_108in_Center.path);
|
.resolve(WPI2020Image.kBlueGoal_108in_Center.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Path getTestMode2022ImagePath() {
|
||||||
|
return getResourcesFolderPath(true)
|
||||||
|
.resolve("testimages")
|
||||||
|
.resolve(WPI2022Image.kTerminal22ft6in.path);
|
||||||
|
}
|
||||||
|
|
||||||
public static Path getTestImagesPath(boolean testMode) {
|
public static Path getTestImagesPath(boolean testMode) {
|
||||||
return getResourcesFolderPath(testMode).resolve("testimages");
|
return getResourcesFolderPath(testMode).resolve("testimages");
|
||||||
}
|
}
|
||||||
@@ -232,7 +259,6 @@ public class TestUtils {
|
|||||||
HighGui.waitKey(timeoutMs);
|
HighGui.waitKey(timeoutMs);
|
||||||
HighGui.destroyAllWindows();
|
HighGui.destroyAllWindows();
|
||||||
} catch (HeadlessException ignored) {
|
} catch (HeadlessException ignored) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user