diff --git a/shared/examplecheck.gradle b/shared/examplecheck.gradle index 644c095cf21..27d90762de8 100644 --- a/shared/examplecheck.gradle +++ b/shared/examplecheck.gradle @@ -103,6 +103,24 @@ task checkExamples(type: Task) { } } +task checkSnippets(type: Task) { + doLast { + def parsedJson = new groovy.json.JsonSlurper().parseText(snippetsFile.text) + fileCheck(parsedJson, snippetsDirectory) + parsedJson.each { + assert it.name != null + assert it.description != null + assert it.tags != null + assert it.tags.findAll { !tagList.contains(it) }.empty + assert it.foldername != null + assert it.gradlebase != null + if (it.gradlebase == 'java') { + assert it.mainclass != null + } + } + } +} + task checkCommands(type: Task) { doLast { def parsedJson = new groovy.json.JsonSlurper().parseText(commandFile.text) @@ -127,3 +145,4 @@ task checkCommands(type: Task) { check.dependsOn checkTemplates check.dependsOn checkExamples check.dependsOn checkCommands +check.dependsOn checkSnippets diff --git a/wpilibcExamples/CMakeLists.txt b/wpilibcExamples/CMakeLists.txt index aaec73c88fe..f79cd15d68c 100644 --- a/wpilibcExamples/CMakeLists.txt +++ b/wpilibcExamples/CMakeLists.txt @@ -5,6 +5,7 @@ include(SubDirList) subdir_list(TEMPLATES ${CMAKE_SOURCE_DIR}/wpilibcExamples/src/main/cpp/templates) subdir_list(EXAMPLES ${CMAKE_SOURCE_DIR}/wpilibcExamples/src/main/cpp/examples) +subdir_list(SNIPPETS ${CMAKE_SOURCE_DIR}/wpilibcExamples/src/main/cpp/snippets) add_custom_target(wpilibcExamples) add_custom_target(wpilibcExamples_test) @@ -63,3 +64,16 @@ foreach(template ${TEMPLATES}) target_link_libraries(${template} wpilibc wpilibNewCommands romiVendordep xrpVendordep) add_dependencies(wpilibcExamples ${template}) endforeach() + +foreach(snippet ${SNIPPETS}) + file( + GLOB_RECURSE sources + src/main/cpp/snippets/${snippet}/cpp/*.cpp + src/main/cpp/snippets/${snippet}/c/*.c + ) + add_executable(snippet${snippet} ${sources}) + wpilib_target_warnings(${snippet}) + target_include_directories(snippet${snippet} PUBLIC src/main/cpp/snippets/${snippet}/include) + target_link_libraries(snippet${snippet} wpilibc wpilibNewCommands romiVendordep xrpVendordep) + add_dependencies(wpilibcExamples snippet${snippet}) +endforeach() diff --git a/wpilibcExamples/build.gradle b/wpilibcExamples/build.gradle index eb1aca52513..aa0aaedef42 100644 --- a/wpilibcExamples/build.gradle +++ b/wpilibcExamples/build.gradle @@ -14,9 +14,20 @@ apply from: "${rootDir}/shared/googletest.gradle" ext.examplesMap = [:] ext.templatesMap = [:] +ext.snippetsMap = [:] -File examplesTree = file("$projectDir/src/main/cpp/examples") -examplesTree.list(new FilenameFilter() { +ext { + templateDirectory = new File("$projectDir/src/main/cpp/templates/") + templateFile = new File("$projectDir/src/main/cpp/templates/templates.json") + exampleDirectory = new File("$projectDir/src/main/cpp/examples/") + exampleFile = new File("$projectDir/src/main/cpp/examples/examples.json") + commandDirectory = new File("$projectDir/src/main/cpp/commands/") + commandFile = new File("$projectDir/src/main/cpp/commands/commands.json") + snippetsDirectory = new File("$projectDir/src/main/cpp/snippets/") + snippetsFile = new File("$projectDir/src/main/cpp/snippets/snippets.json") +} + +exampleDirectory.list(new FilenameFilter() { @Override public boolean accept(File current, String name) { return new File(current, name).isDirectory(); @@ -24,8 +35,7 @@ examplesTree.list(new FilenameFilter() { }).each { examplesMap.put(it, []) } -File templatesTree = file("$projectDir/src/main/cpp/templates") -templatesTree.list(new FilenameFilter() { +templateDirectory.list(new FilenameFilter() { @Override public boolean accept(File current, String name) { return new File(current, name).isDirectory(); @@ -33,6 +43,14 @@ templatesTree.list(new FilenameFilter() { }).each { templatesMap.put(it, []) } +snippetsDirectory.list(new FilenameFilter() { + @Override + public boolean accept(File current, String name) { + return new File(current, name).isDirectory(); + } + }).each { + snippetsMap.put(it, []) + } nativeUtils.platformConfigs.named(nativeUtils.wpi.platforms.windowsx64).configure { linker.args.remove('/DEBUG:FULL') @@ -41,7 +59,7 @@ nativeUtils.platformConfigs.named(nativeUtils.wpi.platforms.windowsx64).configur } ext { - sharedCvConfigs = examplesMap + templatesMap + [commands: []] + sharedCvConfigs = examplesMap + templatesMap + snippetsMap.collectEntries { key, value -> ['snippets' + key, value] } + [commands: []] staticCvConfigs = [:] useJava = false useCpp = true @@ -171,6 +189,57 @@ model { } } } + snippetsMap.each { key, value -> + "snippets${key}"(NativeExecutableSpec) { + targetBuildTypes 'debug' + binaries.all { binary -> + lib project: ':wpilibNewCommands', library: 'wpilibNewCommands', linkage: 'shared' + lib project: ':romiVendordep', library: 'romiVendordep', linkage: 'shared' + lib project: ':xrpVendordep', library: 'xrpVendordep', linkage: 'shared' + lib project: ':wpilibc', library: 'wpilibc', linkage: 'shared' + lib project: ':apriltag', library: 'apriltag', linkage: 'shared' + lib project: ':wpimath', library: 'wpimath', linkage: 'shared' + project(':ntcore').addNtcoreDependency(binary, 'shared') + lib project: ':cscore', library: 'cscore', linkage: 'shared' + project(':hal').addHalDependency(binary, 'shared') + lib project: ':cameraserver', library: 'cameraserver', linkage: 'shared' + lib project: ':wpinet', library: 'wpinet', linkage: 'shared' + lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared' + if (binary.targetPlatform.name == nativeUtils.wpi.platforms.roborio) { + nativeUtils.useRequiredLibrary(binary, 'ni_link_libraries', 'ni_runtime_libraries') + } + if (binary.targetPlatform.name == getCurrentArch()) { + simModules.each { + lib project: ":simulation:$it", library: it, linkage: 'shared' + } + } + } + sources { + cpp { + source { + srcDirs 'src/main/cpp/snippets/' + "${key}" + "/cpp" + include '**/*.cpp' + } + exportedHeaders { + srcDirs 'src/main/cpp/snippets/' + "${key}" + "/include" + include '**/*.h' + } + } + } + sources { + c { + source { + srcDirs 'src/main/cpp/snippets/' + "${key}" + "/c" + include '**/*.c' + } + exportedHeaders { + srcDirs 'src/main/cpp/snippets/' + "${key}" + "/include" + include '**/*.h' + } + } + } + } + } } testSuites { examplesMap.each { key, value -> @@ -207,6 +276,41 @@ model { } } } + testSuites { + snippetsMap.each { key, value -> + def testFolder = new File("${rootDir}/wpilibcExamples/src/test/cpp/snippets/${key}") + if (testFolder.exists()) { + "snippets${key}Test"(GoogleTestTestSuiteSpec) { + for (NativeComponentSpec c : $.components) { + if (c.name == key) { + testing c + break + } + } + sources { + cpp { + source { + srcDirs "src/test/cpp/examples/${key}/cpp" + include '**/*.cpp' + } + exportedHeaders { + srcDirs "src/test/cpp/examples/${key}/include" + } + } + c { + source { + srcDirs "src/test/cpp/examples/${key}/c" + include '**/*.c' + } + exportedHeaders { + srcDirs "src/test/cpp/examples/${key}/include" + } + } + } + } + } + } + } binaries { withType(GoogleTestTestSuiteBinarySpec) { lib project: ':wpilibNewCommands', library: 'wpilibNewCommands', linkage: 'shared' @@ -253,15 +357,6 @@ model { } } -ext { - templateDirectory = new File("$projectDir/src/main/cpp/templates/") - templateFile = new File("$projectDir/src/main/cpp/templates/templates.json") - exampleDirectory = new File("$projectDir/src/main/cpp/examples/") - exampleFile = new File("$projectDir/src/main/cpp/examples/examples.json") - commandDirectory = new File("$projectDir/src/main/cpp/commands/") - commandFile = new File("$projectDir/src/main/cpp/commands/commands.json") -} - model { // Create run tasks for all examples. tasks { diff --git a/wpilibcExamples/src/main/cpp/snippets/Encoder/cpp/Robot.cpp b/wpilibcExamples/src/main/cpp/snippets/Encoder/cpp/Robot.cpp new file mode 100644 index 00000000000..7f736d5c1bd --- /dev/null +++ b/wpilibcExamples/src/main/cpp/snippets/Encoder/cpp/Robot.cpp @@ -0,0 +1,69 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#include + +#include +#include +#include +#include + +/** + * Encoder snippets for frc-docs. + * https://docs.wpilib.org/en/stable/docs/software/hardware-apis/sensors/encoders-software.html + */ +WPI_IGNORE_DEPRECATED +class Robot : public frc::TimedRobot { + public: + Robot() { + // Configures the encoder to return a distance of 4 for every 256 pulses + // Also changes the units of getRate + m_encoder.SetDistancePerPulse(4.0 / 256.0); + // Configures the encoder to consider itself stopped after .1 seconds + m_encoder.SetMaxPeriod(0.1_s); + // Configures the encoder to consider itself stopped when its rate is below + // 10 + m_encoder.SetMinRate(10); + // Reverses the direction of the encoder + m_encoder.SetReverseDirection(true); + // Configures an encoder to average its period measurement over 5 samples + // Can be between 1 and 127 samples + m_encoder.SetSamplesToAverage(5); + } + + void TeleopPeriodic() override { + // Gets the distance traveled + m_encoder.GetDistance(); + + // Gets the current rate of the encoder + m_encoder.GetRate(); + + // Gets whether the encoder is stopped + m_encoder.GetStopped(); + + // Gets the last direction in which the encoder moved + m_encoder.GetDirection(); + + // Gets the current period of the encoder + m_encoder.GetPeriod(); + + // Resets the encoder to read a distance of zero + m_encoder.Reset(); + } + + private: + // Initializes an encoder on DIO pins 0 and 1 + // Defaults to 4X decoding and non-inverted + frc::Encoder m_encoder{0, 1}; + + // Initializes an encoder on DIO pins 0 and 1 + // 2X encoding and non-inverted + frc::Encoder m_encoder2x{0, 1, false, frc::Encoder::EncodingType::k2X}; +}; + +#ifndef RUNNING_FRC_TESTS +int main() { + return frc::StartRobot(); +} +#endif diff --git a/wpilibcExamples/src/main/cpp/snippets/snippets.json b/wpilibcExamples/src/main/cpp/snippets/snippets.json new file mode 100644 index 00000000000..884e075dfdd --- /dev/null +++ b/wpilibcExamples/src/main/cpp/snippets/snippets.json @@ -0,0 +1,12 @@ +[ + { + "name": "Encoder", + "description": "Snippets of Encoder class usage for frc-docs.", + "tags": [ + "Hardware", + "Encoder" + ], + "foldername": "Encoder", + "gradlebase": "cpp" + } +] diff --git a/wpilibjExamples/build.gradle b/wpilibjExamples/build.gradle index 115b2539650..eec38c0a353 100644 --- a/wpilibjExamples/build.gradle +++ b/wpilibjExamples/build.gradle @@ -72,6 +72,8 @@ ext { exampleFile = new File("$projectDir/src/main/java/edu/wpi/first/wpilibj/examples/examples.json") commandDirectory = new File("$projectDir/src/main/java/edu/wpi/first/wpilibj/commands/") commandFile = new File("$projectDir/src/main/java/edu/wpi/first/wpilibj/commands/commands.json") + snippetsDirectory = new File("$projectDir/src/main/java/edu/wpi/first/wpilibj/snippets/") + snippetsFile = new File("$projectDir/src/main/java/edu/wpi/first/wpilibj/snippets/snippets.json") } apply plugin: 'cpp' @@ -203,6 +205,47 @@ model { test.dependsOn(testTask) } } + new groovy.json.JsonSlurper().parseText(snippetsFile.text).each { entry -> + project.tasks.create("runSnippet${entry.foldername}", JavaExec) { run -> + run.group "run snippets" + run.mainClass = "edu.wpi.first.wpilibj.snippets." + entry.foldername + "." + entry.mainclass + run.classpath = sourceSets.main.runtimeClasspath + run.dependsOn it.tasks.install + run.systemProperty 'java.library.path', filePath + doFirst { doFirstTask(run) } + + if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) { + run.jvmArgs = ['-XstartOnFirstThread'] + } + } + project.tasks.create("testSnippet${entry.foldername}", Test) { testTask -> + testTask.group "verification" + testTask.useJUnitPlatform() + testTask.filter { + includeTestsMatching("edu.wpi.first.wpilibj.snippets.${entry.foldername}.*") + setFailOnNoMatchingTests(false) + } + test.filter { + excludeTestsMatching("edu.wpi.first.wpilibj.snippets.${entry.foldername}.*") + setFailOnNoMatchingTests(false) + } + testTask.testClassesDirs = sourceSets.test.output.classesDirs + testTask.classpath = sourceSets.test.runtimeClasspath + testTask.dependsOn it.tasks.install + + testTask.systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true' + testTask.testLogging { + events "failed" + exceptionFormat "full" + } + testTask.systemProperty 'java.library.path', filePath + + if (project.hasProperty('onlylinuxathena') || project.hasProperty('onlylinuxarm32') || project.hasProperty('onlylinuxarm64') || project.hasProperty('onlywindowsarm64')) { + testTask.enabled = false + } + test.dependsOn(testTask) + } + } found = true } diff --git a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/encoder/Main.java b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/encoder/Main.java new file mode 100644 index 00000000000..4fef5feb296 --- /dev/null +++ b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/encoder/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.first.wpilibj.snippets.encoder; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/encoder/Robot.java b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/encoder/Robot.java new file mode 100644 index 00000000000..de1511bd552 --- /dev/null +++ b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/encoder/Robot.java @@ -0,0 +1,62 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.first.wpilibj.snippets.encoder; + +import edu.wpi.first.wpilibj.Encoder; +import edu.wpi.first.wpilibj.TimedRobot; + +/** + * Encoder snippets for frc-docs. + * https://docs.wpilib.org/en/stable/docs/software/hardware-apis/sensors/encoders-software.html + */ +@SuppressWarnings("deprecation") +public class Robot extends TimedRobot { + // Initializes an encoder on DIO pins 0 and 1 + // Defaults to 4X decoding and non-inverted + Encoder m_encoder = new Encoder(0, 1); + + // Initializes an encoder on DIO pins 0 and 1 + // 2X encoding and non-inverted + Encoder m_encoder2x = new Encoder(0, 1, false, Encoder.EncodingType.k2X); + + /** Called once at the beginning of the robot program. */ + public Robot() { + // Configures the encoder to return a distance of 4 for every 256 pulses + // Also changes the units of getRate + m_encoder.setDistancePerPulse(4.0 / 256.0); + // Configures the encoder to consider itself stopped after .1 seconds + m_encoder.setMaxPeriod(0.1); + // Configures the encoder to consider itself stopped when its rate is below 10 + m_encoder.setMinRate(10); + // Reverses the direction of the encoder + m_encoder.setReverseDirection(true); + // Configures an encoder to average its period measurement over 5 samples + // Can be between 1 and 127 samples + m_encoder.setSamplesToAverage(5); + + m_encoder2x.getRate(); + } + + @Override + public void teleopPeriodic() { + // Gets the distance traveled + m_encoder.getDistance(); + + // Gets the current rate of the encoder + m_encoder.getRate(); + + // Gets whether the encoder is stopped + m_encoder.getStopped(); + + // Gets the last direction in which the encoder moved + m_encoder.getDirection(); + + // Gets the current period of the encoder + m_encoder.getPeriod(); + + // Resets the encoder to read a distance of zero + m_encoder.reset(); + } +} diff --git a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/snippets.json b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/snippets.json new file mode 100644 index 00000000000..8e8786f7133 --- /dev/null +++ b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/snippets.json @@ -0,0 +1,13 @@ +[ + { + "name": "Encoder", + "description": "Snippets of Encoder class usage for frc-docs.", + "tags": [ + "Hardware", + "Encoder" + ], + "foldername": "encoder", + "gradlebase": "java", + "mainclass": "Main" + } +]