├── .gitignore
├── README.md
├── _config.yml
├── build.gradle
├── doc
└── images
│ ├── build-common-gradle.png
│ ├── gradle-sync.png
│ ├── gradledepend.png
│ ├── jcenter.png
│ └── teamcode-gradle.png
├── examples
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── org
│ └── openftc
│ └── revextensions2
│ └── examples
│ ├── BulkDataExample.java
│ ├── CurrentMonitorsExample.java
│ ├── HwSwInfoExample.java
│ ├── MiscExamples.java
│ ├── ServoPulseWidthExample.java
│ ├── TemperatureMonitorsExample.java
│ └── VoltageMonitorsExample.java
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── index.md
├── release-aar.gradle
├── rev-extensions-2
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── org
│ └── openftc
│ └── revextensions2
│ ├── ExpansionHubEx.java
│ ├── ExpansionHubMotor.java
│ ├── ExpansionHubServo.java
│ ├── RE2Exception.java
│ ├── RevBulkData.java
│ ├── RevBulkDataException.java
│ ├── RevExtensions2.java
│ ├── Utils.java
│ └── VexMC29.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .idea/
38 |
39 | # Keystore files
40 | # Uncomment the following line if you do not want to check your keystore files in.
41 | #*.jks
42 |
43 | # External native build folder generated in Android Studio 2.2 and later
44 | .externalNativeBuild
45 |
46 | # Google Services (e.g. APIs or Firebase)
47 | google-services.json
48 |
49 | # Freeline
50 | freeline.py
51 | freeline/
52 | freeline_project_description.json
53 |
54 | # fastlane
55 | fastlane/report.xml
56 | fastlane/Preview.html
57 | fastlane/screenshots
58 | fastlane/test_output
59 | fastlane/readme.md
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RevExtensions2
2 |
3 | **NOTE: SDK v4.x/5.x is required to use this**
4 |
5 | **NOTE: an OpenRC-based SDK is NOT required to use this**
6 |
7 | **NOTE: scroll down for installation instructions**
8 |
9 | ### DISCLAIMER:
10 |
11 | Use this at your own risk. **You accept the possibility that using these extra features may cause the SDK to implode and cause you lose F-3 at worlds.**
12 | That being said, I used a few of these features in competition this past season without any issues.
13 |
14 | ## What extra functionality does this add to the SDK?
15 |
16 | - Setting the LED color on the Hub
17 | - Setting the speed of the I2C buses on the Hub
18 | - Querying for total module current draw
19 | - Querying for servo bus current draw [ **broken:** REV firmware bug ]
20 | - Querying for GPIO bus current draw
21 | - Querying for I2C bus current draw
22 | - Querying for individual motor channel current draw
23 | - Reading the 5v monitor
24 | - Reading the 12v monitor
25 | - Queying for the internal temperature inside the Hub [ **broken:** unknown units ]
26 | - Query whether the Expansion Hub is in an over-temp condition
27 | - Query whether each individual motor H-bridge is over-temp
28 | - Query whether phone charging is enabled [ **broken:** REV firmware bug ]
29 | - Enable or disable phone charging
30 | - Setting servo pulse width directly in microseconds
31 | - Reading certain data in bulk from the Hub (can increase your control loop speed)
32 |
33 | The following data can be read in one go:
34 |
35 | - All 4 encoder counts
36 | - All 4 encoder velocities
37 | - All digital pins
38 | - All all analog pins
39 | - Is motor at target position for all 4 motors
40 |
41 | - Query whether a motor has "lost counts" [ **broken:** no idea what this actually does ]
42 | - Query for which firmware version the Hub has installed
43 | - Query for which hardware revision the Hub is
44 | - Convenient `VexMC29` class to prevent the need to manually scale the servo range for the Vex MC29.
45 |
46 | ## How do I install this?
47 |
48 | 1. Open your FTC SDK Android Studio project
49 | 2. Open the `build.common.gradle` file:
50 |
51 | 
52 |
53 | 3. Add `jcenter()` to the `repositories` block at the bottom:
54 |
55 | 
56 |
57 | 4. Open the `build.gradle` file for the TeamCode module:
58 |
59 | 
60 |
61 | 5. At the bottom, add this:
62 |
63 | dependencies {
64 | //NOTE: this is the correct version, the below screenshot is outdated
65 | implementation 'org.openftc:rev-extensions-2:1.2'
66 | }
67 |
68 | When you've done that, the bottom of the file should look like this:
69 |
70 | 
71 |
72 | 6. Now perform a Gradle Sync:
73 |
74 | 
75 |
76 | 7. Wait for Gradle to finish gradling
77 |
78 | 8. Congratulations! You are now ready to use the new features provided by REV Extensions 2!
79 |
80 |
81 | ## Ok now that I've installed it, how do I use this?
82 |
83 | Please see the [examples](examples/src/main/java/org/openftc/revextensions2/examples) folder. More detailed documentation coming soon.
84 |
85 | ## Changelog
86 |
87 | ### v1.2
88 |
89 | - Fix compatibility with SDK v5.x (should still be backwards compatible with v4.x, as the difference was not a compile-time issue)
90 | - **Bugfix:** (Issue #6) Prevent possibility of exception when doing bulk reads during disconnect event
91 | - Add `VexMC29` class, which scales the normal -1 to 1 CRServo PWM range to the range expected by the MC29.
92 | - **API change:** The hardware map is now hotswapped transparently - you no longer need to call `RevExtensions2.init()`
93 | - **API change:** Require units as a parameter to get voltage/current/temperature methods
94 |
95 | ### v1.1
96 |
97 | - Fix compatibility with SDK v4.x (due to API breaking changes, older versions of the SDK are no longer supported)
98 | - Fix `RevBulkData.getMotorCurrentPosition()` and `RevBulkData.getMotorVelocity()` to return the value signed to be consistent with `DcMotor.getMotorCurrentPosition()` and `DcMotorEx.getVelocity()`
99 | - Correct typo in `CurrentMonitorsExample.java`
100 | - Don't ignore reflection exceptions
101 | - Add JavaDoc comments to `RevBulkData.java`
102 | - Refactor hotswapping slightly
103 |
104 | ### v1.0
105 |
106 | - Initial release
107 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-hacker
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.1'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | maven {
23 | url 'https://dl.bintray.com/openftc/maven';
24 | }
25 | }
26 | }
27 |
28 | task clean(type: Delete) {
29 | delete rootProject.buildDir
30 | }
31 |
--------------------------------------------------------------------------------
/doc/images/build-common-gradle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFTC/RevExtensions2/e98d1a55e58353d72985f1871c01adcc0781dfbb/doc/images/build-common-gradle.png
--------------------------------------------------------------------------------
/doc/images/gradle-sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFTC/RevExtensions2/e98d1a55e58353d72985f1871c01adcc0781dfbb/doc/images/gradle-sync.png
--------------------------------------------------------------------------------
/doc/images/gradledepend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFTC/RevExtensions2/e98d1a55e58353d72985f1871c01adcc0781dfbb/doc/images/gradledepend.png
--------------------------------------------------------------------------------
/doc/images/jcenter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFTC/RevExtensions2/e98d1a55e58353d72985f1871c01adcc0781dfbb/doc/images/jcenter.png
--------------------------------------------------------------------------------
/doc/images/teamcode-gradle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFTC/RevExtensions2/e98d1a55e58353d72985f1871c01adcc0781dfbb/doc/images/teamcode-gradle.png
--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/examples/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 |
6 | defaultConfig {
7 | minSdkVersion 19
8 | targetSdkVersion 26
9 | versionCode 1
10 | versionName "1.0"
11 |
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 |
21 | }
22 |
23 | dependencies {
24 | //implementation fileTree(include: ['*.aar'], dir: '../libs')
25 | compileOnly 'org.openftc:hardware-stock:5.0'
26 | compileOnly 'org.openftc:robotcore-stock:5.0'
27 | compileOnly project(':rev-extensions-2')
28 | }
29 |
--------------------------------------------------------------------------------
/examples/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/examples/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/examples/src/main/java/org/openftc/revextensions2/examples/BulkDataExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2.examples;
23 |
24 | import com.qualcomm.robotcore.eventloop.opmode.OpMode;
25 | import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
26 | import com.qualcomm.robotcore.hardware.AnalogInput;
27 | import com.qualcomm.robotcore.hardware.DigitalChannel;
28 |
29 | import org.openftc.revextensions2.ExpansionHubEx;
30 | import org.openftc.revextensions2.ExpansionHubMotor;
31 | import org.openftc.revextensions2.RevBulkData;
32 |
33 | @TeleOp(group = "RevExtensions2Examples")
34 | public class BulkDataExample extends OpMode
35 | {
36 | RevBulkData bulkData;
37 | AnalogInput a0, a1, a2, a3;
38 | DigitalChannel d0, d1, d2, d3, d4, d5, d6, d7;
39 | ExpansionHubMotor motor0, motor1, motor2, motor3;
40 | ExpansionHubEx expansionHub;
41 |
42 | @Override
43 | public void init()
44 | {
45 | /*
46 | * Before init() was called on this user code, REV Extensions 2
47 | * was notified via OpModeManagerNotifier.Notifications and
48 | * it automatically took care of initializing the new objects
49 | * in the hardwaremap for you. Historically, you would have
50 | * needed to call RevExtensions2.init()
51 | */
52 | expansionHub = hardwareMap.get(ExpansionHubEx.class, "Expansion Hub 2");
53 | motor0 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor0");
54 | motor1 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor1");
55 | motor2 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor2");
56 | motor3 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor3");
57 | a0 = hardwareMap.analogInput.get("a0");
58 | a1 = hardwareMap.analogInput.get("a1");
59 | a2 = hardwareMap.analogInput.get("a2");
60 | a3 = hardwareMap.analogInput.get("a3");
61 | d0 = hardwareMap.digitalChannel.get("d0");
62 | d1 = hardwareMap.digitalChannel.get("d1");
63 | d2 = hardwareMap.digitalChannel.get("d2");
64 | d3 = hardwareMap.digitalChannel.get("d3");
65 | d4 = hardwareMap.digitalChannel.get("d4");
66 | d5 = hardwareMap.digitalChannel.get("d5");
67 | d6 = hardwareMap.digitalChannel.get("d6");
68 | d7 = hardwareMap.digitalChannel.get("d7");
69 | }
70 |
71 | @Override
72 | public void loop()
73 | {
74 | /*
75 | * ------------------------------------------------------------------------------------------------
76 | * Bulk data
77 | *
78 | * NOTE: While you could get all of this information by issuing many separate commands,
79 | * the amount of time required to fetch the information would increase drastically. By
80 | * reading all of this information in one command, we can loop at over 300Hz (!!!)
81 | * ------------------------------------------------------------------------------------------------
82 | */
83 |
84 | bulkData = expansionHub.getBulkInputData();
85 |
86 | String header =
87 | "**********************************\n" +
88 | "BULK DATA EXAMPLE \n" +
89 | "**********************************\n";
90 | telemetry.addLine(header);
91 |
92 | /*
93 | * Encoders
94 | */
95 | telemetry.addData("M0 enocder", bulkData.getMotorCurrentPosition(motor0));
96 | telemetry.addData("M1 encoder", bulkData.getMotorCurrentPosition(motor1));
97 | telemetry.addData("M2 encoder", bulkData.getMotorCurrentPosition(motor2));
98 | telemetry.addData("M3 encoder", bulkData.getMotorCurrentPosition(motor3));
99 |
100 | /*
101 | * Encoder velocities
102 | */
103 | telemetry.addData("M0 velocity", bulkData.getMotorVelocity(motor0));
104 | telemetry.addData("M1 velocity", bulkData.getMotorVelocity(motor1));
105 | telemetry.addData("M2 velocity", bulkData.getMotorVelocity(motor2));
106 | telemetry.addData("M3 velocity", bulkData.getMotorVelocity(motor3));
107 |
108 | /*
109 | * Is motor at target position?
110 | */
111 | telemetry.addData("M0 at target pos", bulkData.isMotorAtTargetPosition(motor0));
112 | telemetry.addData("M1 at target pos", bulkData.isMotorAtTargetPosition(motor1));
113 | telemetry.addData("M2 at target pos", bulkData.isMotorAtTargetPosition(motor2));
114 | telemetry.addData("M3 at target pos", bulkData.isMotorAtTargetPosition(motor3));
115 |
116 | /*
117 | * Analog voltages
118 | */
119 | telemetry.addData("A0", bulkData.getAnalogInputValue(a0));
120 | telemetry.addData("A1", bulkData.getAnalogInputValue(a1));
121 | telemetry.addData("A2", bulkData.getAnalogInputValue(a2));
122 | telemetry.addData("A3", bulkData.getAnalogInputValue(a3));
123 |
124 | /*
125 | * Digital states
126 | */
127 | telemetry.addData("D0", bulkData.getDigitalInputState(d0));
128 | telemetry.addData("D1", bulkData.getDigitalInputState(d1));
129 | telemetry.addData("D2", bulkData.getDigitalInputState(d2));
130 | telemetry.addData("D3", bulkData.getDigitalInputState(d3));
131 | telemetry.addData("D4", bulkData.getDigitalInputState(d4));
132 | telemetry.addData("D5", bulkData.getDigitalInputState(d5));
133 | telemetry.addData("D6", bulkData.getDigitalInputState(d6));
134 | telemetry.addData("D7", bulkData.getDigitalInputState(d7));
135 |
136 | telemetry.update();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/examples/src/main/java/org/openftc/revextensions2/examples/CurrentMonitorsExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2.examples;
23 |
24 | import com.qualcomm.robotcore.eventloop.opmode.OpMode;
25 | import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
26 |
27 | import org.openftc.revextensions2.ExpansionHubEx;
28 | import org.openftc.revextensions2.ExpansionHubMotor;
29 |
30 | @TeleOp(group = "RevExtensions2Examples")
31 | public class CurrentMonitorsExample extends OpMode
32 | {
33 | ExpansionHubMotor motor0, motor1, motor2, motor3;
34 | ExpansionHubEx expansionHub;
35 |
36 | @Override
37 | public void init()
38 | {
39 | /*
40 | * Before init() was called on this user code, REV Extensions 2
41 | * was notified via OpModeManagerNotifier.Notifications and
42 | * it automatically took care of initializing the new objects
43 | * in the hardwaremap for you. Historically, you would have
44 | * needed to call RevExtensions2.init()
45 | */
46 | expansionHub = hardwareMap.get(ExpansionHubEx.class, "Expansion Hub 2");
47 | motor0 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor0");
48 | motor1 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor1");
49 | motor2 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor2");
50 | motor3 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor3");
51 | }
52 |
53 | @Override
54 | public void loop()
55 | {
56 | /*
57 | * ------------------------------------------------------------------------------------------------
58 | * Current monitors - NOTE: units are milliamps
59 | * ------------------------------------------------------------------------------------------------
60 | */
61 |
62 | String header =
63 | "**********************************\n" +
64 | "CURRENT MONITORING EXAMPLE \n" +
65 | "NOTE: UNITS ARE AMPS \n" +
66 | "**********************************\n";
67 | telemetry.addLine(header);
68 |
69 | telemetry.addData("Total current", expansionHub.getTotalModuleCurrentDraw(ExpansionHubEx.CurrentDrawUnits.AMPS));
70 | telemetry.addData("I2C current", expansionHub.getI2cBusCurrentDraw(ExpansionHubEx.CurrentDrawUnits.AMPS));
71 | telemetry.addData("GPIO current", expansionHub.getGpioBusCurrentDraw(ExpansionHubEx.CurrentDrawUnits.AMPS));
72 | telemetry.addData("M0 current", motor0.getCurrentDraw(ExpansionHubEx.CurrentDrawUnits.AMPS));
73 | telemetry.addData("M1 current", motor1.getCurrentDraw(ExpansionHubEx.CurrentDrawUnits.AMPS));
74 | telemetry.addData("M2 current", motor2.getCurrentDraw(ExpansionHubEx.CurrentDrawUnits.AMPS));
75 | telemetry.addData("M3 current", motor3.getCurrentDraw(ExpansionHubEx.CurrentDrawUnits.AMPS));
76 |
77 | telemetry.update();
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/examples/src/main/java/org/openftc/revextensions2/examples/HwSwInfoExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2.examples;
23 |
24 | import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
25 | import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
26 |
27 | import org.openftc.revextensions2.ExpansionHubEx;
28 |
29 | @TeleOp(group = "RevExtensions2Examples")
30 | public class HwSwInfoExample extends LinearOpMode
31 | {
32 | ExpansionHubEx expansionHub;
33 |
34 | @Override
35 | public void runOpMode() throws InterruptedException
36 | {
37 | /*
38 | * Before init() was called on this user code, REV Extensions 2
39 | * was notified via OpModeManagerNotifier.Notifications and
40 | * it automatically took care of initializing the new objects
41 | * in the hardwaremap for you. Historically, you would have
42 | * needed to call RevExtensions2.init()
43 | */
44 | expansionHub = hardwareMap.get(ExpansionHubEx.class, "Expansion Hub 2");
45 |
46 | /*
47 | * ------------------------------------------------------------------------------------------------
48 | * HW/SW info
49 | * ------------------------------------------------------------------------------------------------
50 | */
51 |
52 | String header =
53 | "**********************************\n" +
54 | "HW/SW INFO EXAMPLE \n" +
55 | "**********************************\n";
56 | telemetry.addLine(header);
57 |
58 | telemetry.addData("Firmware", expansionHub.getFirmwareVersion());
59 | telemetry.addData("Hardware revision", expansionHub.getHardwareRevision());
60 | telemetry.update();
61 |
62 | waitForStart();
63 | while (opModeIsActive());
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/examples/src/main/java/org/openftc/revextensions2/examples/MiscExamples.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2.examples;
23 |
24 | import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
25 | import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
26 |
27 | import org.openftc.revextensions2.ExpansionHubEx;
28 |
29 | @TeleOp(group = "RevExtensions2Examples")
30 | public class MiscExamples extends LinearOpMode
31 | {
32 | ExpansionHubEx expansionHub;
33 |
34 | @Override
35 | public void runOpMode() throws InterruptedException
36 | {
37 | /*
38 | * Before init() was called on this user code, REV Extensions 2
39 | * was notified via OpModeManagerNotifier.Notifications and
40 | * it automatically took care of initializing the new objects
41 | * in the hardwaremap for you. Historically, you would have
42 | * needed to call RevExtensions2.init()
43 | */
44 | expansionHub = hardwareMap.get(ExpansionHubEx.class, "Expansion Hub 2");
45 |
46 | String header =
47 | "**********************************\n" +
48 | "MISC. EXAMPLES \n" +
49 | "**********************************\n";
50 | telemetry.addLine(header);
51 |
52 | /*
53 | * Setting ExpansionHub LED color
54 | */
55 | expansionHub.setLedColor(255, 0, 0);
56 | telemetry.addLine("Setting Hub LED color");
57 |
58 | /*
59 | * Setting ExpansionHub I2C bus speed
60 | */
61 | expansionHub.setAllI2cBusSpeeds(ExpansionHubEx.I2cBusSpeed.FAST_400K);
62 | telemetry.addLine("Setting speed of all I2C buses");
63 |
64 | telemetry.update();
65 |
66 | waitForStart();
67 | while (opModeIsActive());
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/examples/src/main/java/org/openftc/revextensions2/examples/ServoPulseWidthExample.java:
--------------------------------------------------------------------------------
1 | package org.openftc.revextensions2.examples;
2 |
3 | import com.qualcomm.robotcore.eventloop.opmode.OpMode;
4 | import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
5 |
6 | import org.openftc.revextensions2.ExpansionHubServo;
7 |
8 | @TeleOp(group = "RevExtensions2Examples")
9 | public class ServoPulseWidthExample extends OpMode
10 | {
11 | ExpansionHubServo servo;
12 |
13 | @Override
14 | public void init()
15 | {
16 | /*
17 | * Before init() was called on this user code, REV Extensions 2
18 | * was notified via OpModeManagerNotifier.Notifications and
19 | * it automatically took care of initializing the new objects
20 | * in the hardwaremap for you. Historically, you would have
21 | * needed to call RevExtensions2.init()
22 | */
23 | servo = (ExpansionHubServo) hardwareMap.servo.get("servo");
24 | }
25 |
26 | @Override
27 | public void loop()
28 | {
29 | String header =
30 | "**********************************\n" +
31 | "SERVO PULSE WIDTH EXAMPLE \n" +
32 | "**********************************\n";
33 | telemetry.addLine(header);
34 |
35 | servo.setPwmEnable(); // <-- IMPORTANT: make sure the servo is enabled, otherwise setPulseWidthUs() will appear to have no effect
36 | servo.setPulseWidthUs(1000);
37 |
38 | telemetry.addLine("Setting servo pulse width directly...");
39 | telemetry.update();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/src/main/java/org/openftc/revextensions2/examples/TemperatureMonitorsExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2.examples;
23 |
24 | import com.qualcomm.robotcore.eventloop.opmode.OpMode;
25 | import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
26 |
27 | import org.openftc.revextensions2.ExpansionHubEx;
28 | import org.openftc.revextensions2.ExpansionHubMotor;
29 |
30 | @TeleOp(group = "RevExtensions2Examples")
31 | public class TemperatureMonitorsExample extends OpMode
32 | {
33 | ExpansionHubMotor motor0, motor1, motor2, motor3;
34 | ExpansionHubEx expansionHub;
35 |
36 | @Override
37 | public void init()
38 | {
39 | /*
40 | * Before init() was called on this user code, REV Extensions 2
41 | * was notified via OpModeManagerNotifier.Notifications and
42 | * it automatically took care of initializing the new objects
43 | * in the hardwaremap for you. Historically, you would have
44 | * needed to call RevExtensions2.init()
45 | */
46 | expansionHub = hardwareMap.get(ExpansionHubEx.class, "Expansion Hub 2");
47 | motor0 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor0");
48 | motor1 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor1");
49 | motor2 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor2");
50 | motor3 = (ExpansionHubMotor) hardwareMap.dcMotor.get("motor3");
51 | }
52 |
53 | @Override
54 | public void loop()
55 | {
56 | /*
57 | * ------------------------------------------------------------------------------------------------
58 | * Temperature monitors
59 | * ------------------------------------------------------------------------------------------------
60 | */
61 |
62 | String header =
63 | "**********************************\n" +
64 | "TEMPERATURE MONITORS EXAMPLE \n" +
65 | "**********************************\n";
66 | telemetry.addLine(header);
67 |
68 | telemetry.addData("Module temp", expansionHub.getInternalTemperature(ExpansionHubEx.TemperatureUnits.FAHRENHEIT) + "F");
69 | telemetry.addData("Module over temp", expansionHub.isModuleOverTemp());
70 | telemetry.addData("M0 H-bridge over temp", motor0.isBridgeOverTemp());
71 | telemetry.addData("M1 H-bridge over temp", motor1.isBridgeOverTemp());
72 | telemetry.addData("M2 H-bridge over temp", motor2.isBridgeOverTemp());
73 | telemetry.addData("M3 H-bridge over temp", motor3.isBridgeOverTemp());
74 |
75 | telemetry.update();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/examples/src/main/java/org/openftc/revextensions2/examples/VoltageMonitorsExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2.examples;
23 |
24 | import com.qualcomm.robotcore.eventloop.opmode.OpMode;
25 | import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
26 |
27 | import org.openftc.revextensions2.ExpansionHubEx;
28 |
29 | @TeleOp(group = "RevExtensions2Examples")
30 | public class VoltageMonitorsExample extends OpMode
31 | {
32 | ExpansionHubEx expansionHub;
33 |
34 | @Override
35 | public void init()
36 | {
37 | /*
38 | * Before init() was called on this user code, REV Extensions 2
39 | * was notified via OpModeManagerNotifier.Notifications and
40 | * it automatically took care of initializing the new objects
41 | * in the hardwaremap for you. Historically, you would have
42 | * needed to call RevExtensions2.init()
43 | */
44 | expansionHub = hardwareMap.get(ExpansionHubEx.class, "Expansion Hub 2");
45 | }
46 |
47 | @Override
48 | public void loop()
49 | {
50 | /*
51 | * ------------------------------------------------------------------------------------------------
52 | * Voltage monitors
53 | * ------------------------------------------------------------------------------------------------
54 | */
55 |
56 | String header =
57 | "**********************************\n" +
58 | "VOLTAGE MONITORS EXAMPLE \n" +
59 | "**********************************\n";
60 | telemetry.addLine(header);
61 |
62 | telemetry.addData("5v monitor", expansionHub.read5vMonitor(ExpansionHubEx.VoltageUnits.VOLTS)); //Voltage from the phone
63 | telemetry.addData("12v monitor", expansionHub.read12vMonitor(ExpansionHubEx.VoltageUnits.VOLTS)); //Battery voltage
64 | telemetry.update();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenFTC/RevExtensions2/e98d1a55e58353d72985f1871c01adcc0781dfbb/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Jun 02 15:16:59 EDT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/index.md:
--------------------------------------------------------------------------------
1 | Hello world.
2 |
--------------------------------------------------------------------------------
/release-aar.gradle:
--------------------------------------------------------------------------------
1 | // ./gradlew clean build generateRelease
2 | apply plugin: 'maven'
3 |
4 | def groupId = project.PUBLISH_GROUP_ID
5 | def artifactId = project.PUBLISH_ARTIFACT_ID
6 | def version = project.PUBLISH_VERSION
7 |
8 | def localReleaseDest = "${buildDir}/release/${version}"
9 |
10 | task androidJavadocs(type: Javadoc) {
11 | failOnError = false
12 | source = android.sourceSets.main.java.srcDirs
13 | ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
14 | classpath += files(ext.androidJar)
15 | }
16 |
17 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
18 | classifier = 'javadoc'
19 | from androidJavadocs.destinationDir
20 | }
21 |
22 | task androidSourcesJar(type: Jar) {
23 | classifier = 'sources'
24 | from android.sourceSets.main.java.srcDirs
25 | }
26 |
27 | uploadArchives {
28 | repositories.mavenDeployer {
29 | pom.groupId = groupId
30 | pom.artifactId = artifactId
31 | pom.version = version
32 | // Add other pom properties here if you want (developer details / licenses)
33 | repository(url: "file://${localReleaseDest}")
34 | }
35 | }
36 |
37 | task zipRelease(type: Zip) {
38 | from localReleaseDest
39 | destinationDir buildDir
40 | archiveName "release-${version}.zip"
41 | }
42 |
43 | task generateRelease {
44 | doLast {
45 | println "Release ${version} can be found at ${localReleaseDest}/"
46 | println "Release ${version} zipped can be found ${buildDir}/release-${version}.zip"
47 | }
48 | }
49 |
50 | generateRelease.dependsOn(uploadArchives)
51 | generateRelease.dependsOn(zipRelease)
52 |
53 |
54 | artifacts {
55 | archives androidSourcesJar
56 | archives androidJavadocsJar
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/rev-extensions-2/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/rev-extensions-2/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | ext {
4 | PUBLISH_GROUP_ID = 'org.openftc'
5 | PUBLISH_ARTIFACT_ID = 'rev-extensions-2'
6 | PUBLISH_VERSION = '1.2'
7 | }
8 |
9 | android {
10 | compileSdkVersion 26
11 |
12 | defaultConfig {
13 | minSdkVersion 19
14 | targetSdkVersion 26
15 | versionCode 2
16 | versionName "1.2"
17 |
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 |
27 | lintOptions {
28 | abortOnError false
29 | }
30 | }
31 |
32 | dependencies {
33 | //compileOnly fileTree(include: ['*.aar'], dir: '../libs')
34 | compileOnly 'org.openftc:hardware-stock:5.0'
35 | compileOnly 'org.openftc:robotcore-stock:5.0'
36 | }
37 |
38 | apply from: '../release-aar.gradle'
--------------------------------------------------------------------------------
/rev-extensions-2/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/java/org/openftc/revextensions2/ExpansionHubEx.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2;
23 |
24 | import android.graphics.Color;
25 |
26 | import com.qualcomm.hardware.lynx.LynxCommExceptionHandler;
27 | import com.qualcomm.hardware.lynx.LynxModule;
28 | import com.qualcomm.hardware.lynx.LynxNackException;
29 | import com.qualcomm.hardware.lynx.commands.core.LynxGetADCCommand;
30 | import com.qualcomm.hardware.lynx.commands.core.LynxGetADCResponse;
31 | import com.qualcomm.hardware.lynx.commands.core.LynxGetBulkInputDataCommand;
32 | import com.qualcomm.hardware.lynx.commands.core.LynxGetBulkInputDataResponse;
33 | import com.qualcomm.hardware.lynx.commands.core.LynxI2cConfigureChannelCommand;
34 | import com.qualcomm.hardware.lynx.commands.core.LynxPhoneChargeControlCommand;
35 | import com.qualcomm.hardware.lynx.commands.core.LynxPhoneChargeQueryCommand;
36 | import com.qualcomm.hardware.lynx.commands.core.LynxPhoneChargeQueryResponse;
37 | import com.qualcomm.hardware.lynx.commands.core.LynxSetServoPulseWidthCommand;
38 | import com.qualcomm.hardware.lynx.commands.standard.LynxGetModuleStatusCommand;
39 | import com.qualcomm.hardware.lynx.commands.standard.LynxGetModuleStatusResponse;
40 | import com.qualcomm.hardware.lynx.commands.standard.LynxSetModuleLEDColorCommand;
41 | import com.qualcomm.robotcore.hardware.HardwareDevice;
42 | import com.qualcomm.robotcore.hardware.configuration.LynxConstants;
43 |
44 | import org.firstinspires.ftc.robotcore.internal.system.AppUtil;
45 |
46 | import java.util.regex.Matcher;
47 | import java.util.regex.Pattern;
48 |
49 | /**
50 | * Provides an implementation of the REV Expansion Hub's features that are not
51 | * included in the standard FTC SDK.
52 | */
53 | public class ExpansionHubEx extends LynxCommExceptionHandler implements HardwareDevice
54 | {
55 | private LynxModule expansionHub;
56 |
57 | /*
58 | * Don't use this constructor in user-code; this object will be
59 | * hotswapped into the hardwareMap at runtime.
60 | */
61 | ExpansionHubEx(LynxModule expansionHub)
62 | {
63 | this.expansionHub = expansionHub;
64 | }
65 |
66 | public LynxModule getStandardModule()
67 | {
68 | return expansionHub;
69 | }
70 |
71 | /***
72 | * Set the color of the Expansion Hub's RGB status LED
73 | *
74 | * @param r red value
75 | * @param g green value
76 | * @param b blue value
77 | */
78 | public synchronized void setLedColor(int r, int g, int b)
79 | {
80 | if(r > 255 || g > 255 || b > 255)
81 | {
82 | throw new IllegalArgumentException();
83 | }
84 |
85 | setLedColor((byte)r, (byte)g, (byte)b);
86 | }
87 |
88 | /***
89 | * Set the color of the Expansion Hub's RGB status LED
90 | *
91 | * @param r red value
92 | * @param g green value
93 | * @param b blue value
94 | */
95 | public synchronized void setLedColor(byte r, byte g, byte b)
96 | {
97 | LynxSetModuleLEDColorCommand colorCommand = new LynxSetModuleLEDColorCommand(expansionHub, r, g, b);
98 | try
99 | {
100 | colorCommand.send();
101 | }
102 | catch (InterruptedException | LynxNackException e)
103 | {
104 | handleException(e);
105 | }
106 | }
107 |
108 | /***
109 | * Set the color of the Expansion Hub's RGB status LED
110 | *
111 | * @param resId the resId of a color you have defined in your colors.xml file
112 | */
113 | public synchronized void setLedColor(int resId)
114 | {
115 | int color = AppUtil.getInstance().getRootActivity().getResources().getColor(resId);
116 |
117 | byte red = (byte) Color.red(color);
118 | byte green = (byte) Color.green(color);
119 | byte blue = (byte) Color.blue(color);
120 |
121 | setLedColor(red, green, blue);
122 | }
123 |
124 | public enum I2cBusSpeed
125 | {
126 | STANDARD_100K,
127 | FAST_400K,
128 | FASTPLUS_1M,
129 | HIGH_3_4M
130 | }
131 |
132 | /***
133 | * Set the speed of all of the I2C buses on the Expansion Hub
134 | * in one go!
135 | *
136 | * @param speed the speed to set all of the buses to
137 | */
138 | public synchronized void setAllI2cBusSpeeds(I2cBusSpeed speed)
139 | {
140 | for(int i = 0; i < LynxConstants.NUMBER_OF_I2C_BUSSES; i++)
141 | {
142 | setI2cBusSpeed(i, speed);
143 | }
144 | }
145 |
146 | /***
147 | * Set the speed of an individual I2C bus on the Expansion Hub
148 | *
149 | * @param bus the bus to set the speed of (0...3)
150 | * @param speed the speed to set the bus to
151 | */
152 | public synchronized void setI2cBusSpeed(int bus, I2cBusSpeed speed)
153 | {
154 | LynxI2cConfigureChannelCommand.SpeedCode speedCode = LynxI2cConfigureChannelCommand.SpeedCode.STANDARD_100K;
155 |
156 | switch (speed)
157 | {
158 | case STANDARD_100K:
159 | speedCode = LynxI2cConfigureChannelCommand.SpeedCode.STANDARD_100K;
160 | break;
161 |
162 | case FAST_400K:
163 | speedCode = LynxI2cConfigureChannelCommand.SpeedCode.FAST_400K;
164 | break;
165 |
166 | case FASTPLUS_1M:
167 | speedCode = LynxI2cConfigureChannelCommand.SpeedCode.FASTPLUS_1M;
168 | break;
169 |
170 | case HIGH_3_4M:
171 | speedCode = LynxI2cConfigureChannelCommand.SpeedCode.HIGH_3_4M;
172 | break;
173 | }
174 |
175 | LynxI2cConfigureChannelCommand command = new LynxI2cConfigureChannelCommand(expansionHub, bus, speedCode);
176 | try
177 | {
178 | command.send();
179 | }
180 | catch (LynxNackException | InterruptedException e)
181 | {
182 | handleException(e);
183 | }
184 | }
185 |
186 | public enum CurrentDrawUnits
187 | {
188 | MILLIAMPS,
189 | AMPS
190 | }
191 |
192 | /**
193 | * Get the total current draw for the entire Expansion Hub.
194 | *
195 | * @param units the units to return the current draw in
196 | * @return Current draw for the entire Expansion Hub
197 | */
198 | public synchronized double getTotalModuleCurrentDraw(CurrentDrawUnits units)
199 | {
200 | LynxGetADCCommand command = new LynxGetADCCommand(expansionHub, LynxGetADCCommand.Channel.BATTERY_CURRENT, LynxGetADCCommand.Mode.ENGINEERING);
201 | try
202 | {
203 | LynxGetADCResponse response = command.sendReceive();
204 |
205 | int ma = response.getValue();
206 |
207 | if(units == CurrentDrawUnits.MILLIAMPS)
208 | {
209 | return ma;
210 | }
211 | else if(units == CurrentDrawUnits.AMPS)
212 | {
213 | return ma/1000d;
214 | }
215 | }
216 | catch (InterruptedException | RuntimeException | LynxNackException e)
217 | {
218 | handleException(e);
219 | }
220 | return 0;
221 | }
222 |
223 | /**
224 | * Get the current draw for the servo bus.
225 | *
226 | * @param units the units to return the current draw in
227 | * @return Current draw of the servo bus
228 | * @deprecated This feature currently does not work (likely a bug in the Expansion Hub firmware).
229 | */
230 | @Deprecated
231 | public synchronized double getServoBusCurrentDraw(CurrentDrawUnits units)
232 | {
233 | LynxGetADCCommand.Channel channel = LynxGetADCCommand.Channel.SERVO_CURRENT;
234 |
235 | LynxGetADCCommand command = new LynxGetADCCommand(expansionHub, channel, LynxGetADCCommand.Mode.ENGINEERING);
236 | try
237 | {
238 | LynxGetADCResponse response = command.sendReceive();
239 |
240 | int ma = response.getValue();
241 |
242 | if(units == CurrentDrawUnits.MILLIAMPS)
243 | {
244 | return ma;
245 | }
246 | else if(units == CurrentDrawUnits.AMPS)
247 | {
248 | return ma/1000d;
249 | }
250 | }
251 | catch (InterruptedException | RuntimeException | LynxNackException e)
252 | {
253 | handleException(e);
254 | }
255 | return 0;
256 | }
257 |
258 | /***
259 | * Get the total current draw for the GPIO bus
260 | *
261 | * @param units the units to return the current draw in
262 | * @return current draw of the GPIO bus
263 | */
264 | public synchronized double getGpioBusCurrentDraw(CurrentDrawUnits units)
265 | {
266 | LynxGetADCCommand.Channel channel = LynxGetADCCommand.Channel.GPIO_CURRENT;
267 |
268 | LynxGetADCCommand command = new LynxGetADCCommand(expansionHub, channel, LynxGetADCCommand.Mode.ENGINEERING);
269 | try
270 | {
271 | LynxGetADCResponse response = command.sendReceive();
272 |
273 | int ma = response.getValue();
274 |
275 | if(units == CurrentDrawUnits.MILLIAMPS)
276 | {
277 | return ma;
278 | }
279 | else if(units == CurrentDrawUnits.AMPS)
280 | {
281 | return ma/1000d;
282 | }
283 | }
284 | catch (InterruptedException | RuntimeException | LynxNackException e)
285 | {
286 | handleException(e);
287 | }
288 | return 0;
289 | }
290 |
291 | /***
292 | * Get the total current draw for the I2C bus
293 | *
294 | * @param units the units to return the current draw in
295 | * @return the current draw of the I2C bus
296 | */
297 | public synchronized double getI2cBusCurrentDraw(CurrentDrawUnits units)
298 | {
299 | LynxGetADCCommand.Channel channel = LynxGetADCCommand.Channel.I2C_BUS_CURRENT;
300 |
301 | LynxGetADCCommand command = new LynxGetADCCommand(expansionHub, channel, LynxGetADCCommand.Mode.ENGINEERING);
302 | try
303 | {
304 | LynxGetADCResponse response = command.sendReceive();
305 |
306 | int ma = response.getValue();
307 |
308 | if(units == CurrentDrawUnits.MILLIAMPS)
309 | {
310 | return ma;
311 | }
312 | else if(units == CurrentDrawUnits.AMPS)
313 | {
314 | return ma/1000d;
315 | }
316 | }
317 | catch (InterruptedException | RuntimeException | LynxNackException e)
318 | {
319 | handleException(e);
320 | }
321 | return 0;
322 | }
323 |
324 | public enum VoltageUnits
325 | {
326 | MILLIVOLTS,
327 | VOLTS
328 | }
329 |
330 | /***
331 | * Get the voltage reported by the Hub's 5v rail monitor
332 | *
333 | * @param units the units to return the voltage in
334 | * @return the voltage reported by the Hub's 5v monitor
335 | */
336 | public synchronized double read5vMonitor(VoltageUnits units)
337 | {
338 | LynxGetADCCommand.Channel channel = LynxGetADCCommand.Channel.FIVE_VOLT_MONITOR;
339 |
340 | LynxGetADCCommand command = new LynxGetADCCommand(expansionHub, channel, LynxGetADCCommand.Mode.ENGINEERING);
341 | try
342 | {
343 | LynxGetADCResponse response = command.sendReceive();
344 |
345 | int mv = response.getValue();
346 |
347 | if(units == VoltageUnits.MILLIVOLTS)
348 | {
349 | return mv;
350 | }
351 | else if(units == VoltageUnits.VOLTS)
352 | {
353 | return mv/1000d;
354 | }
355 | }
356 | catch (InterruptedException | RuntimeException | LynxNackException e)
357 | {
358 | handleException(e);
359 | }
360 | return 0;
361 | }
362 |
363 | /***
364 | * Get the voltage reported by the Hub's 12v rail monitor
365 | *
366 | * @param units the units to return the voltage in
367 | * @return the voltage reported by the Hub's 12v monitor
368 | */
369 | public synchronized double read12vMonitor(VoltageUnits units)
370 | {
371 | LynxGetADCCommand.Channel channel = LynxGetADCCommand.Channel.BATTERY_MONITOR;
372 |
373 | LynxGetADCCommand command = new LynxGetADCCommand(expansionHub, channel, LynxGetADCCommand.Mode.ENGINEERING);
374 | try
375 | {
376 | LynxGetADCResponse response = command.sendReceive();
377 |
378 | int mv = response.getValue();
379 |
380 | if(units == VoltageUnits.MILLIVOLTS)
381 | {
382 | return mv;
383 | }
384 | else if(units == VoltageUnits.VOLTS)
385 | {
386 | return mv/1000d;
387 | }
388 | }
389 | catch (InterruptedException | RuntimeException | LynxNackException e)
390 | {
391 | handleException(e);
392 | }
393 | return 0;
394 | }
395 |
396 | public enum TemperatureUnits
397 | {
398 | CELSIUS,
399 | FAHRENHEIT
400 | }
401 |
402 | /***
403 | * Get the temperature reported by the Hub's internal temperature sensor
404 | *
405 | * @param units the units to return the temperature in
406 | * @return the Hub's internal temperature
407 | */
408 | public synchronized double getInternalTemperature(TemperatureUnits units)
409 | {
410 | LynxGetADCCommand.Channel channel = LynxGetADCCommand.Channel.CONTROLLER_TEMPERATURE;
411 |
412 | LynxGetADCCommand command = new LynxGetADCCommand(expansionHub, channel, LynxGetADCCommand.Mode.ENGINEERING);
413 | try
414 | {
415 | LynxGetADCResponse response = command.sendReceive();
416 |
417 | int degC = response.getValue();
418 |
419 | if(units == TemperatureUnits.CELSIUS)
420 | {
421 | return degC;
422 | }
423 | else if(units == TemperatureUnits.FAHRENHEIT)
424 | {
425 | return (degC*(9d/5d)) + 32;
426 | }
427 | }
428 | catch (InterruptedException | RuntimeException | LynxNackException e)
429 | {
430 | handleException(e);
431 | }
432 | return 0;
433 | }
434 |
435 | /***
436 | * Query if the Lynx Module is in an over-temp condition
437 | *
438 | * @return boolean indicating if the module is over-temp
439 | */
440 | public synchronized boolean isModuleOverTemp()
441 | {
442 | LynxGetModuleStatusCommand command = new LynxGetModuleStatusCommand(expansionHub);
443 |
444 | try
445 | {
446 | LynxGetModuleStatusResponse response = command.sendReceive();
447 | return response.isControllerOverTemp();
448 | }
449 |
450 | catch (Exception e)
451 | {
452 | handleException(e);
453 | }
454 |
455 | return false;
456 | }
457 |
458 | /***
459 | * Query if the Lynx Module has the phone charge feature enabled
460 | * @deprecated because this seems to lock up the Hub internally and crash the SDK
461 | *
462 | * @return boolean indicating if the module has the phone charge feature enabled
463 | */
464 | @Deprecated
465 | public synchronized boolean isPhoneChargeEnabled()
466 | {
467 | LynxPhoneChargeQueryCommand command = new LynxPhoneChargeQueryCommand(expansionHub);
468 |
469 | try
470 | {
471 | LynxPhoneChargeQueryResponse response = command.sendReceive();
472 | return response.isChargeEnabled();
473 | }
474 |
475 | catch (Exception e)
476 | {
477 | handleException(e);
478 | }
479 |
480 | return false;
481 | }
482 |
483 | /***
484 | * Control whether or not the Lynx Module's phone charging function is enabled
485 | *
486 | * @param chargeEnabled true for enabled, false for disabled
487 | */
488 | public synchronized void setPhoneChargeEnabled(boolean chargeEnabled)
489 | {
490 | LynxPhoneChargeControlCommand controlCommand = new LynxPhoneChargeControlCommand(expansionHub, chargeEnabled);
491 | try
492 | {
493 | controlCommand.send();
494 | }
495 | catch (InterruptedException | LynxNackException e)
496 | {
497 | handleException(e);
498 | }
499 | }
500 |
501 | /***
502 | * Set the pulse width output of a servo port directly, rather than using
503 | * the -1 to 1 range from the SDK
504 | *
505 | * @param port the servo port to set the pulse width of
506 | * @param uS the pulse width (in uS) to set the above servo port to
507 | */
508 | public synchronized void setServoPulseWidth(int port, int uS)
509 | {
510 | LynxSetServoPulseWidthCommand command = new LynxSetServoPulseWidthCommand(expansionHub, port, uS);
511 |
512 | try
513 | {
514 | command.send();
515 | }
516 | catch (InterruptedException | LynxNackException e)
517 | {
518 | handleException(e);
519 | }
520 | }
521 |
522 | /***
523 | * Grab a bunch of useful data from the Lynx module in one go
524 | *
525 | * @return an object that contains a bunch of useful data
526 | */
527 | public synchronized RevBulkData getBulkInputData()
528 | {
529 | LynxGetBulkInputDataCommand command = new LynxGetBulkInputDataCommand(expansionHub);
530 |
531 | try
532 | {
533 | LynxGetBulkInputDataResponse response = command.sendReceive();
534 | return new RevBulkData(response, expansionHub);
535 | }
536 |
537 | catch (Exception e)
538 | {
539 | handleException(e);
540 | }
541 |
542 | return null;
543 | }
544 |
545 | /**
546 | * Get the amount of current that a given motor is pulling from its H-bridge
547 | *
548 | * @param units the units to return the current draw in
549 | * @param port the port of the motor in question
550 | * @return the current draw in milliamps
551 | */
552 | public synchronized double getMotorCurrentDraw(CurrentDrawUnits units, int port)
553 | {
554 | LynxConstants.validateMotorZ(port);
555 |
556 | LynxGetADCCommand.Channel channel = null;
557 |
558 | if (port == 0)
559 | {
560 | channel = LynxGetADCCommand.Channel.MOTOR0_CURRENT;
561 | }
562 | else if (port == 1)
563 | {
564 | channel = LynxGetADCCommand.Channel.MOTOR1_CURRENT;
565 | }
566 | else if (port == 2)
567 | {
568 | channel = LynxGetADCCommand.Channel.MOTOR2_CURRENT;
569 | }
570 | else if (port == 3)
571 | {
572 | channel = LynxGetADCCommand.Channel.MOTOR3_CURRENT;
573 | }
574 |
575 | LynxGetADCCommand command = new LynxGetADCCommand(expansionHub, channel, LynxGetADCCommand.Mode.ENGINEERING);
576 |
577 | try
578 | {
579 | LynxGetADCResponse response = command.sendReceive();
580 |
581 | int ma = response.getValue();
582 |
583 | if(units == CurrentDrawUnits.MILLIAMPS)
584 | {
585 | return ma;
586 | }
587 | else if(units == CurrentDrawUnits.AMPS)
588 | {
589 | return ma/1000d;
590 | }
591 | }
592 | catch (InterruptedException | RuntimeException | LynxNackException e)
593 | {
594 | handleException(e);
595 | }
596 |
597 | return 0;
598 | }
599 |
600 | /***
601 | * Query as to whether the H-bridge for a given motor port is over-temp
602 | *
603 | * @param port the motor port in question
604 | * @return boolean indicating the H-bridge is over-temp
605 | */
606 | public synchronized boolean isMotorBridgeOverTemp(int port)
607 | {
608 | LynxGetModuleStatusCommand command = new LynxGetModuleStatusCommand(expansionHub);
609 |
610 | try
611 | {
612 | LynxGetModuleStatusResponse response = command.sendReceive();
613 | return response.isMotorBridgeOverTemp(port);
614 | }
615 |
616 | catch (Exception e)
617 | {
618 | handleException(e);
619 | }
620 |
621 | return false;
622 | }
623 |
624 | /***
625 | * Query as to whether a given motor has lost (encoder?) counts
626 | * @deprecated because I have no idea what this actually does
627 | *
628 | * @param port the port of the motor in question
629 | * @return boolean indicating whether the motor has lost (encoder?) counts
630 | */
631 | @Deprecated
632 | public synchronized boolean hasMotorLostCounts(int port)
633 | {
634 | LynxGetModuleStatusCommand command = new LynxGetModuleStatusCommand(expansionHub);
635 |
636 | try
637 | {
638 | LynxGetModuleStatusResponse response = command.sendReceive();
639 | return response.hasMotorLostCounts(port);
640 | }
641 |
642 | catch (Exception e)
643 | {
644 | e.printStackTrace();
645 | }
646 |
647 | return false;
648 | }
649 |
650 | /***
651 | * Query as to which firmware this Expansion Hub is running
652 | *
653 | * @return firmware version string, in th format of maj.min.eng
654 | */
655 | public synchronized String getFirmwareVersion()
656 | {
657 | //HW: 20, Maj: 1, Min: 7, Eng: 0
658 |
659 | String inputstring = expansionHub.getFirmwareVersionString();
660 |
661 | if(inputstring.equals("unknown firmware") || inputstring.equals("firmware version unavailable"))
662 | {
663 | return inputstring;
664 | }
665 |
666 | int majVer = regexField("Maj", inputstring);
667 | int minVer = regexField("Min", inputstring);
668 | int engVer = regexField("Eng", inputstring);
669 |
670 | return String.format("%s.%s.%s", majVer, minVer, engVer);
671 | }
672 |
673 | /***
674 | * Ask the Expansion Hub which hardware revision it is
675 | *
676 | * @return the hardware revision
677 | */
678 | public synchronized int getHardwareRevision()
679 | {
680 | //HW: 20, Maj: 1, Min: 7, Eng: 0
681 |
682 | String inputstring = expansionHub.getFirmwareVersionString();
683 |
684 | if(inputstring.equals("unknown firmware") || inputstring.equals("firmware version unavailable"))
685 | {
686 | return -1;
687 | }
688 |
689 | return regexField("HW", inputstring);
690 | }
691 |
692 | private int regexField(String thing, String input)
693 | {
694 | Pattern pattern = Pattern.compile(thing + ":\\ \\d+");
695 | Matcher matcher = pattern.matcher(input);
696 | matcher.find();
697 |
698 | String string = matcher.group();
699 |
700 | return regexNum(string);
701 | }
702 |
703 | private int regexNum(String str)
704 | {
705 | Pattern pattern = Pattern.compile("\\d+");
706 | Matcher matcher = pattern.matcher(str);
707 | matcher.find();
708 |
709 | return Integer.parseInt(matcher.group());
710 | }
711 |
712 | //-----------------------------------------------------------------------------------------
713 | // Ignore the following methods....
714 | //
715 | // They're only here because in order to have this object hot-injected into the hardwareMap,
716 | // it needs to implement HardwareDevice. And well, in order to implement HardwareDevice, we
717 | // need to implement these methods. Sooo yeah...
718 | //-----------------------------------------------------------------------------------------
719 |
720 | @Override
721 | public Manufacturer getManufacturer()
722 | {
723 | return expansionHub.getManufacturer();
724 | }
725 |
726 | @Override
727 | public String getDeviceName()
728 | {
729 | return expansionHub.getDeviceName();
730 | }
731 |
732 | @Override
733 | public String getConnectionInfo()
734 | {
735 | return expansionHub.getConnectionInfo();
736 | }
737 |
738 | @Override
739 | public int getVersion()
740 | {
741 | return expansionHub.getVersion();
742 | }
743 |
744 | @Override
745 | public void resetDeviceConfigurationForOpMode()
746 | {
747 | expansionHub.resetDeviceConfigurationForOpMode();
748 | }
749 |
750 | @Override
751 | public void close()
752 | {
753 | expansionHub.close();
754 | }
755 | }
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/java/org/openftc/revextensions2/ExpansionHubMotor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2;
23 |
24 | import com.qualcomm.hardware.lynx.LynxController;
25 | import com.qualcomm.robotcore.hardware.DcMotor;
26 | import com.qualcomm.robotcore.hardware.DcMotorImplEx;
27 | import org.openftc.revextensions2.ExpansionHubEx.CurrentDrawUnits;
28 |
29 | /**
30 | * Extends a DcMotorImplEx to provide access to new features.
31 | * Note: motor MUST be attached to an Expansion Hub.
32 | */
33 | public class ExpansionHubMotor extends DcMotorImplEx
34 | {
35 | private ExpansionHubEx expansionHubEx;
36 |
37 | /*
38 | * Don't use this constructor in user-code; this object will be
39 | * hotswapped into the hardwareMap at runtime.
40 | */
41 | ExpansionHubMotor(DcMotor motor)
42 | {
43 | super(motor.getController(), motor.getPortNumber(), motor.getDirection(), motor.getMotorType());
44 | expansionHubEx = new ExpansionHubEx(Utils.getLynxFromController((LynxController) motor.getController()));
45 | }
46 |
47 | /**
48 | * Get the amount of current this motor is pulling from its H-bridge
49 | *
50 | * @return the current draw in milliamps
51 | */
52 | public double getCurrentDraw(CurrentDrawUnits units)
53 | {
54 | return expansionHubEx.getMotorCurrentDraw(units, getPortNumber());
55 | }
56 |
57 | /***
58 | * Query as to whether the H-bridge for this motor is over-temp
59 | *
60 | * @return boolean indicating the H-bridge is over-temp
61 | */
62 | public boolean isBridgeOverTemp()
63 | {
64 | return expansionHubEx.isMotorBridgeOverTemp(getPortNumber());
65 | }
66 |
67 | /***
68 | * Query as to whether this motor has lost (encoder?) counts
69 | * @deprecated because I have no idea what this actually does
70 | *
71 | * @return boolean indicating whether the motor has lost (encoder?) counts
72 | */
73 | @Deprecated
74 | public boolean hasLostCounts()
75 | {
76 | return expansionHubEx.hasMotorLostCounts(getPortNumber());
77 | }
78 | }
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/java/org/openftc/revextensions2/ExpansionHubServo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 | package org.openftc.revextensions2;
22 |
23 | import com.qualcomm.hardware.lynx.LynxController;
24 | import com.qualcomm.robotcore.hardware.Servo;
25 | import com.qualcomm.robotcore.hardware.ServoControllerEx;
26 | import com.qualcomm.robotcore.hardware.ServoImplEx;
27 | import com.qualcomm.robotcore.hardware.configuration.typecontainers.ServoConfigurationType;
28 |
29 | /**
30 | * Extends a ServoImplEx to provide access to new features.
31 | * Note: servo MUST be attached to an Expansion Hub.
32 | */
33 |
34 | public class ExpansionHubServo extends ServoImplEx
35 | {
36 | private ExpansionHubEx expansionHubEx;
37 |
38 | /*
39 | * Don't use this constructor in user-code; this object will be
40 | * hotswapped into the hardwareMap at runtime.
41 | */
42 | ExpansionHubServo(Servo servo)
43 | {
44 | super(
45 | (ServoControllerEx)servo.getController(),
46 | servo.getPortNumber(),
47 | servo.getDirection(),
48 | ServoConfigurationType.getStandardServoType());
49 |
50 | expansionHubEx = new ExpansionHubEx(Utils.getLynxFromController((LynxController) servo.getController()));
51 | }
52 |
53 | /***
54 | * Set the pulse width output of this servo port directly, rather than using
55 | * the -1 to 1 range from the SDK
56 | *
57 | * @param uS the pulse width (in uS) to set this servo port to
58 | */
59 | public void setPulseWidthUs(int uS)
60 | {
61 | expansionHubEx.setServoPulseWidth(getPortNumber(), uS);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/java/org/openftc/revextensions2/RE2Exception.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2;
23 |
24 | class RE2Exception extends RuntimeException
25 | {
26 | RE2Exception(){}
27 |
28 | RE2Exception(String msg)
29 | {
30 | super(msg);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/java/org/openftc/revextensions2/RevBulkData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2;
23 |
24 | import com.qualcomm.hardware.lynx.LynxAnalogInputController;
25 | import com.qualcomm.hardware.lynx.LynxController;
26 | import com.qualcomm.hardware.lynx.LynxDcMotorController;
27 | import com.qualcomm.hardware.lynx.LynxDigitalChannelController;
28 | import com.qualcomm.hardware.lynx.LynxModule;
29 | import com.qualcomm.hardware.lynx.commands.core.LynxGetBulkInputDataResponse;
30 | import com.qualcomm.robotcore.hardware.AnalogInput;
31 | import com.qualcomm.robotcore.hardware.AnalogInputController;
32 | import com.qualcomm.robotcore.hardware.DcMotor;
33 | import com.qualcomm.robotcore.hardware.DcMotorSimple;
34 | import com.qualcomm.robotcore.hardware.DigitalChannel;
35 | import com.qualcomm.robotcore.hardware.DigitalChannelController;
36 | import com.qualcomm.robotcore.hardware.DigitalChannelImpl;
37 | import com.qualcomm.robotcore.hardware.configuration.typecontainers.MotorConfigurationType;
38 |
39 | import org.firstinspires.ftc.robotcore.external.navigation.Rotation;
40 |
41 | import java.lang.reflect.Field;
42 |
43 | /**
44 | * This class is a wrapper over LynxGetBulkInputDataResponse that provides
45 | * easier-to-use methods to access the underlying data
46 | */
47 |
48 | public class RevBulkData
49 | {
50 | private LynxGetBulkInputDataResponse response;
51 | private LynxModule module;
52 |
53 | /***
54 | * Constructor
55 | *
56 | * @param response the raw response over which we are to be a wrapper
57 | *
58 | * @param module the Lynx module that this response came from;
59 | * used to verify that this response actually
60 | * contains the device information the user
61 | * was after. (They might have issued this command
62 | * to the wrong LynxModule)
63 | */
64 | RevBulkData(LynxGetBulkInputDataResponse response, LynxModule module)
65 | {
66 | this.response = response;
67 | this.module = module;
68 | }
69 |
70 | // see DcMotorImpl#getOperationalDirection()
71 | private static DcMotorSimple.Direction getMotorOperationalDirection(DcMotor dcMotor)
72 | {
73 | MotorConfigurationType motorType = dcMotor.getMotorType();
74 | DcMotorSimple.Direction direction = dcMotor.getDirection();
75 | if (motorType.getOrientation() == Rotation.CCW)
76 | {
77 | return direction.inverted();
78 | }
79 | else
80 | {
81 | return direction;
82 | }
83 | }
84 |
85 | //-----------------------------------------------------------------------------------
86 | // Encoder counts
87 | //-----------------------------------------------------------------------------------
88 |
89 | /***
90 | * Get the encoder count of a motor port on the Expansion Hub
91 | * from which this bulk data response came. Please note that
92 | * the sign of the value will NOT be adjusted for whether or
93 | * not the motor was set to reverse mode; for that please use
94 | * the corresponding method that takes a DcMotor parameter
95 | * instead of the raw port number.
96 | *
97 | * @param motorNum the motor port for which to get the
98 | * encoder count [0-3]
99 | *
100 | * @return the encoder count (retrieved from this bulk packet)
101 | * of the motor port specified by the motorNum parameter
102 | */
103 | public int getMotorCurrentPosition(int motorNum)
104 | {
105 | return response.getEncoder(motorNum);
106 | }
107 |
108 | /***
109 | * Gets the encoder count for a motor that is connected to the
110 | * Expansion Hub from which this bulk data packet came. If the
111 | * user passes in a motor that is connected to a different Hub
112 | * than the one that this packet came from, an exception is thrown
113 | * Additionally, the sign of the value is adjusted to account for
114 | * whether the user set the motor direction to reverse.
115 | *
116 | * @param motor the motor for which to retrieve the encoder count
117 | *
118 | * @return the encoder count (retrieved from this bulk packet) for
119 | * the DcMotor object passed in
120 | */
121 | public int getMotorCurrentPosition(DcMotor motor)
122 | {
123 | throwIfMotorInvalid(motor);
124 | int position = getMotorCurrentPosition(motor.getPortNumber());
125 | if (getMotorOperationalDirection(motor) == DcMotorSimple.Direction.REVERSE)
126 | {
127 | return -position;
128 | }
129 | else
130 | {
131 | return position;
132 | }
133 | }
134 |
135 | //-----------------------------------------------------------------------------------
136 | // Encoder velocities
137 | //-----------------------------------------------------------------------------------
138 |
139 | /***
140 | * Get the encoder velocity of a motor port on the Expansion Hub
141 | * from which this bulk data response came. Please note that
142 | * the sign of the value will NOT be adjusted for whether or
143 | * not the motor was set to reverse mode; for that please use
144 | * the corresponding method that takes a DcMotor parameter
145 | * instead of the raw port number.
146 | *
147 | * @param motorNum the motor port for which to get the
148 | * encoder velocity [0-3]
149 | *
150 | * @return the encoder velocity (retrieved from this bulk packet)
151 | * of the motor port specified by the motorNum parameter
152 | */
153 | public int getMotorVelocity(int motorNum)
154 | {
155 | return response.getVelocity(motorNum);
156 | }
157 |
158 | /***
159 | * Gets the encoder velocity for a motor that is connected to the
160 | * Expansion Hub from which this bulk data packet came. If the
161 | * user passes in a motor that is connected to a different Hub
162 | * than the one that this packet came from, an exception is thrown
163 | * Additionally, the sign of the value is adjusted to account for
164 | * whether the user set the motor direction to reverse.
165 | *
166 | * @param motor the motor for which to retrieve the encoder velocity
167 | *
168 | * @return the encoder velocity (retrieved from this bulk packet) for
169 | * the DcMotor object passed in
170 | */
171 | public int getMotorVelocity(DcMotor motor)
172 | {
173 | throwIfMotorInvalid(motor);
174 | int velocity = getMotorVelocity(motor.getPortNumber());
175 | if (getMotorOperationalDirection(motor) == DcMotorSimple.Direction.REVERSE)
176 | {
177 | return -velocity;
178 | }
179 | else
180 | {
181 | return velocity;
182 | }
183 | }
184 |
185 | //-----------------------------------------------------------------------------------
186 | // Position control at target position
187 | //-----------------------------------------------------------------------------------
188 |
189 | /***
190 | * Checks whether a motor on a given port of the Expansion Hub
191 | * from which this bulk data response came is at it's target
192 | * encoder position
193 | *
194 | * @param motorNum the port for which to check whether the motor
195 | * is at it's target encoder position
196 | *
197 | * @return whether the motor in the specified port is at its target
198 | * encoder position as retrieved from this bulk packet
199 | */
200 | public boolean isMotorAtTargetPosition(int motorNum)
201 | {
202 | return response.isAtTarget(motorNum);
203 | }
204 |
205 | /***
206 | * Checks whether a given motor connected to the Expansion Hub
207 | * from which this bulk data response came is at it's target
208 | * encoder position. If the user passes in a motor that is connected
209 | * to a different Hub than the one that this packet came from, an
210 | * exception is thrown
211 | *
212 | * @param motor the motor for which to check if the target encoder
213 | * position has been reached
214 | *
215 | * @return whether the motor in the specified port is at its target
216 | * encoder position as retrieved from this bulk packet
217 | */
218 | public boolean isMotorAtTargetPosition(DcMotor motor)
219 | {
220 | throwIfMotorInvalid(motor);
221 | return isMotorAtTargetPosition(motor.getPortNumber());
222 | }
223 |
224 | //-----------------------------------------------------------------------------------
225 | // Analog I/Os
226 | //-----------------------------------------------------------------------------------
227 |
228 | /***
229 | * Gets the ADC value of an analog pin on the Expansion Hub from
230 | * which this bulk data packet came.
231 | *
232 | * @param pin the analog pin for which to get the ADC value [0-3]
233 | *
234 | * @return the ADC value (retrieved from this bulk packet) for the
235 | * specified analog pin
236 | */
237 | public int getAnalogInputValue(int pin)
238 | {
239 | return response.getAnalogInput(pin);
240 | }
241 |
242 | /***
243 | * Gets the ADC value of an analog device that is connected to the
244 | * Expansion Hub from which this bulk data packet came. If the
245 | * user passes in a device that is connected to a different Hub
246 | * than the one that this packet came from, an exception is thrown
247 | *
248 | * @param input the analog device for which to get the ADC value
249 | *
250 | * @return the ADC value (retrieved from this bulk packet) for the
251 | * AnalogInput object passed in
252 | */
253 | public int getAnalogInputValue(AnalogInput input)
254 | {
255 | AnalogInputController controller = null;
256 | int port = -1;
257 |
258 | try
259 | {
260 | Field controllerField = AnalogInput.class.getDeclaredField("controller");
261 | controllerField.setAccessible(true);
262 | controller = (AnalogInputController) controllerField.get(input);
263 |
264 | Field channelField = AnalogInput.class.getDeclaredField("channel");
265 | channelField.setAccessible(true);
266 | port = (int) channelField.get(input);
267 | }
268 | catch (Exception e)
269 | {
270 | throw new RE2Exception("Failed to reflect on AnalogInput! Please report this as an issue on the GitHub repository.");
271 | }
272 |
273 | if(!(controller instanceof LynxAnalogInputController))
274 | {
275 | throw new RevBulkDataException(String.format("AnalogInput %s is not attached to a Lynx module!", Utils.getHwMapName(input)));
276 | }
277 |
278 | if(!validateLynxController((LynxController) controller))
279 | {
280 | throw new RevBulkDataException(String.format("AnalogInput %s is attached to a different Lynx module than the one that this bulk command was issued to!", Utils.getHwMapName(input)));
281 | }
282 |
283 | return getAnalogInputValue(port);
284 | }
285 |
286 | //-----------------------------------------------------------------------------------
287 | // Digital I/Os
288 | //-----------------------------------------------------------------------------------
289 |
290 | /***
291 | * Gets the state of a digital pin on the Expansion Hub from which
292 | * this bulk data packet came.
293 | *
294 | * @param pin the digital pin for which to get the state [0-7]
295 | *
296 | * @return the state (retrieved from this bulk packet) of the
297 | * specified digital pin
298 | */
299 | public boolean getDigitalInputState(int pin)
300 | {
301 | return response.getDigitalInput(pin);
302 | }
303 |
304 | /***
305 | * Gets the state of a digital device that is connected to the
306 | * Expansion Hub from which this bulk data packet came. If the
307 | * user passes in a device that is connected to a different Hub
308 | * than the one that this packet came from, an exception is thrown
309 | *
310 | * @param digitalChannel the digital device for which to get the state
311 | *
312 | * @return the state (retrieved from this bulk packet) for the
313 | * DigitalChannel object passed in
314 | */
315 | public boolean getDigitalInputState(DigitalChannel digitalChannel)
316 | {
317 | DigitalChannelController controller = null;
318 | int port = -1;
319 |
320 | try
321 | {
322 | Field controllerField = DigitalChannelImpl.class.getDeclaredField("controller");
323 | controllerField.setAccessible(true);
324 | controller = (DigitalChannelController) controllerField.get(digitalChannel);
325 |
326 | Field channelField = DigitalChannelImpl.class.getDeclaredField("channel");
327 | channelField.setAccessible(true);
328 | port = (int) channelField.get(digitalChannel);
329 | }
330 | catch (Exception e)
331 | {
332 | throw new RE2Exception("Failed to reflect on DigitalChannelImpl! Please report this as an issue on the GitHub repository.");
333 | }
334 |
335 | if(!(controller instanceof LynxDigitalChannelController))
336 | {
337 | throw new RevBulkDataException(String.format("DigitalChannel %s is not attached to a Lynx module!", Utils.getHwMapName(digitalChannel)));
338 | }
339 |
340 | if(!validateLynxController((LynxController) controller))
341 | {
342 | throw new RevBulkDataException(String.format("DigitalChannel %s is attached to a different Lynx module than the one that this bulk command was issued to!", Utils.getHwMapName(digitalChannel)));
343 | }
344 |
345 | return getDigitalInputState(port);
346 | }
347 |
348 | //-----------------------------------------------------------------------------------
349 | // Utility functions
350 | //-----------------------------------------------------------------------------------
351 |
352 | /***
353 | * Checks to see if the motor passed in is not attached to a Lynx module,
354 | * or if it is attached to a different Lynx module than the one that this
355 | * bulk packet came from. If either of those two conditions is true, an
356 | * exception is thrown.
357 | *
358 | * @param motor the motor to validate
359 | */
360 | private void throwIfMotorInvalid(DcMotor motor)
361 | {
362 | // Is this motor attached to a Lynx module?
363 | if(!(motor.getController() instanceof LynxDcMotorController))
364 | {
365 | throw new RevBulkDataException(String.format("Motor %s is not attached to a Lynx module!", Utils.getHwMapName(motor)));
366 | }
367 |
368 | // Is this motor attached to a different Lynx module than the one
369 | // that this packet came from?
370 | if(!validateLynxController((LynxController) motor.getController()))
371 | {
372 | throw new RevBulkDataException(String.format("Motor %s is attached to a different Lynx module than the one that this bulk command was issued to!", Utils.getHwMapName(motor)));
373 | }
374 | }
375 |
376 | /***
377 | * Checks to see whether a Lynx controller is attached to the Lynx
378 | * module that this packet came from
379 | *
380 | * @param controller the controller to validate
381 | *
382 | * @return whether or not the controller is attached to the Lynx
383 | * module that this packet came from
384 | */
385 | private boolean validateLynxController(LynxController controller)
386 | {
387 | return validateLynxModule(Utils.getLynxFromController(controller));
388 | }
389 |
390 | /***
391 | * Checks to see whether a Lynx module passed in is the same one
392 | * that this packet came from
393 | *
394 | * @param moduleToValidate the module to validate
395 | *
396 | * @return whether or not a Lynx module passed in is the same one
397 | * that this packet came from
398 | */
399 | private boolean validateLynxModule(LynxModule moduleToValidate)
400 | {
401 | //TODO: can we just replace with an '=='?
402 | return moduleToValidate.getModuleAddress() == module.getModuleAddress();
403 | }
404 | }
405 |
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/java/org/openftc/revextensions2/RevBulkDataException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2;
23 |
24 | class RevBulkDataException extends RE2Exception
25 | {
26 | RevBulkDataException(){}
27 |
28 | RevBulkDataException(String msg)
29 | {
30 | super(msg);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/java/org/openftc/revextensions2/RevExtensions2.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2;
23 |
24 | import android.content.Context;
25 |
26 | import com.qualcomm.robotcore.eventloop.opmode.AnnotatedOpModeManager;
27 | import com.qualcomm.robotcore.eventloop.opmode.OpMode;
28 | import com.qualcomm.robotcore.eventloop.opmode.OpModeManagerNotifier;
29 | import com.qualcomm.robotcore.eventloop.opmode.OpModeRegistrar;
30 | import com.qualcomm.robotcore.util.RobotLog;
31 |
32 | import org.firstinspires.ftc.robotcore.internal.opmode.OpModeManagerImpl;
33 |
34 | /***
35 | * This class manages hotswapping of the hardwareMap
36 | */
37 |
38 | class RevExtensions2
39 | {
40 | /*
41 | * NOTE: We cannot simply pass `new OpModeNotifications()` inline to the call
42 | * to register the listener, because the SDK stores the list of listeners in
43 | * a WeakReference set. This causes the object to be garbage collected because
44 | * nothing else is holding a reference to it.
45 | */
46 | private static final OpModeNotifications opModeNotifications = new OpModeNotifications();
47 |
48 | /*
49 | * By annotating this method with @OpModeRegistrar, it will be called
50 | * automatically by the SDK as it is scanning all the classes in the app
51 | * (for @Teleop, etc.) while it is "starting" the robot.
52 | */
53 | @OpModeRegistrar
54 | public static void setupOpModeListenerOnStartRobot(Context context, AnnotatedOpModeManager manager)
55 | {
56 | /*
57 | * Because this is called every time the robot is "restarted", one
58 | * would think that we should have a boolean to check whether we've
59 | * already registered this listener to prevent registering duplicate
60 | * listeners. However, the OpModeManager that we register with
61 | * is a child of FtcEventLoop, and the EventLoop is re-created every
62 | * time the robot is "restarted". So thus, we do actually need to
63 | * register the listener every time this method is called.
64 | */
65 | Utils.getOpModeManager().registerListener(opModeNotifications);
66 | }
67 |
68 | private static class OpModeNotifications implements OpModeManagerNotifier.Notifications
69 | {
70 | @Override
71 | public void onOpModePreInit(OpMode opMode)
72 | {
73 | /*
74 | * We only hotswap the hardware map if this is NOT the
75 | * "default" (STOP ROBOT) OpMode
76 | */
77 | if(!(opMode instanceof OpModeManagerImpl.DefaultOpMode))
78 | {
79 | RobotLog.dd("RevExtensions2", "Hotswapping hardware map");
80 | Utils.hotswapHardwareMap();
81 | }
82 | }
83 |
84 | @Override
85 | public void onOpModePreStart(OpMode opMode)
86 | {
87 |
88 | }
89 |
90 | @Override
91 | public void onOpModePostStop(OpMode opMode)
92 | {
93 | /*
94 | * We only deswap the hardware map if this is NOT the
95 | * "default" (STOP ROBOT) OpMode
96 | */
97 | if(!(opMode instanceof OpModeManagerImpl.DefaultOpMode))
98 | {
99 | RobotLog.dd("RevExtensions2", "Deswapping hardware map");
100 | Utils.deswapHardwareMap();
101 | }
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/java/org/openftc/revextensions2/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 |
22 | package org.openftc.revextensions2;
23 |
24 | import com.qualcomm.hardware.lynx.LynxController;
25 | import com.qualcomm.hardware.lynx.LynxDcMotorController;
26 | import com.qualcomm.hardware.lynx.LynxModule;
27 | import com.qualcomm.hardware.lynx.LynxServoController;
28 | import com.qualcomm.robotcore.hardware.DcMotor;
29 | import com.qualcomm.robotcore.hardware.DcMotorEx;
30 | import com.qualcomm.robotcore.hardware.DcMotorImplEx;
31 | import com.qualcomm.robotcore.hardware.HardwareDevice;
32 | import com.qualcomm.robotcore.hardware.HardwareMap;
33 | import com.qualcomm.robotcore.hardware.Servo;
34 | import com.qualcomm.robotcore.hardware.ServoControllerEx;
35 | import com.qualcomm.robotcore.hardware.ServoImplEx;
36 | import com.qualcomm.robotcore.hardware.configuration.typecontainers.ServoConfigurationType;
37 |
38 | import org.firstinspires.ftc.robotcore.internal.opmode.OpModeManagerImpl;
39 | import org.firstinspires.ftc.robotcore.internal.system.AppUtil;
40 |
41 | import java.lang.reflect.Field;
42 | import java.util.ArrayList;
43 | import java.util.HashMap;
44 | import java.util.Map;
45 |
46 | /**
47 | * This class does Blackmagic
48 | */
49 |
50 | class Utils
51 | {
52 | static OpModeManagerImpl getOpModeManager()
53 | {
54 | return OpModeManagerImpl.getOpModeManagerOfActivity(AppUtil.getInstance().getRootActivity());
55 | }
56 |
57 | static HardwareMap getHardwareMap()
58 | {
59 | return getOpModeManager().getHardwareMap();
60 | }
61 |
62 | static void hotswapHardwareMap()
63 | {
64 | HardwareMap map = getHardwareMap();
65 |
66 | swapStandardMotorsForLynx(map);
67 | swapStandardServosForLynx(map);
68 | addExpansionHubExForEachLynxModule(map);
69 | }
70 |
71 | static void deswapHardwareMap()
72 | {
73 | HardwareMap map = getHardwareMap();
74 |
75 | deswapLynxMotors(map);
76 | deswapLynxServos(map);
77 | removeExpansionHubExForEachLynxModule(map);
78 | }
79 |
80 | //------------------------------------------------------------------------------------------------------------------------------------------
81 | // Swapping
82 | //-------------------------------------------------------------------------------------------------------------------------------------------
83 |
84 | private static void swapStandardMotorsForLynx(HardwareMap map)
85 | {
86 | //-----------------------------------------------------------------------------------
87 | // Motors: standard --> Lynx
88 | //-----------------------------------------------------------------------------------
89 |
90 | ArrayList> motorsToRecreateAsLynx = new ArrayList<>();
91 |
92 | // TODO: Process both map.dcMotor and the root map.
93 | for (Map.Entry entry : map.dcMotor.entrySet())
94 | {
95 | if (!(entry.getValue() instanceof ExpansionHubMotor)
96 | && entry.getValue() instanceof DcMotorEx
97 | && entry.getValue().getController() instanceof LynxDcMotorController)
98 | {
99 | motorsToRecreateAsLynx.add(entry);
100 | }
101 | }
102 |
103 | if (!motorsToRecreateAsLynx.isEmpty())
104 | {
105 | for (Map.Entry entry : motorsToRecreateAsLynx)
106 | {
107 | map.dcMotor.remove(entry.getKey());
108 | }
109 |
110 | for (Map.Entry entry : motorsToRecreateAsLynx)
111 | {
112 | map.dcMotor.put(entry.getKey(), new ExpansionHubMotor(entry.getValue()));
113 | }
114 | }
115 | }
116 |
117 | private static void swapStandardServosForLynx(HardwareMap map)
118 | {
119 | //-----------------------------------------------------------------------------------
120 | // Servos: standard --> Lynx
121 | //-----------------------------------------------------------------------------------
122 |
123 | ArrayList> servosToRecreateAsLynx = new ArrayList<>();
124 |
125 | // TODO: Process both map.servo and the root map.
126 | for (Map.Entry entry : map.servo.entrySet())
127 | {
128 | if (!(entry.getValue() instanceof ExpansionHubServo)
129 | && entry.getValue() instanceof ServoImplEx
130 | && entry.getValue().getController() instanceof LynxServoController)
131 | {
132 | servosToRecreateAsLynx.add(entry);
133 | }
134 | }
135 |
136 | if (!servosToRecreateAsLynx.isEmpty())
137 | {
138 | for (Map.Entry entry : servosToRecreateAsLynx)
139 | {
140 | map.servo.remove(entry.getKey());
141 | }
142 |
143 | for (Map.Entry entry : servosToRecreateAsLynx)
144 | {
145 | map.servo.put(entry.getKey(), new ExpansionHubServo(entry.getValue()));
146 | }
147 | }
148 | }
149 |
150 | private static void addExpansionHubExForEachLynxModule(HardwareMap map)
151 | {
152 | //-----------------------------------------------------------------------------------
153 | // LynxModules --+> ExpansionHubEx
154 | //-----------------------------------------------------------------------------------
155 |
156 | HashMap enhancedLynxModulesToInject = new HashMap<>();
157 |
158 | for (LynxModule module : map.getAll(LynxModule.class))
159 | {
160 | if (!hwMapContainsEnhancedModule(module))
161 | {
162 | enhancedLynxModulesToInject.put(getHwMapName(module), new ExpansionHubEx(module));
163 | }
164 | }
165 |
166 | for (Map.Entry entry : enhancedLynxModulesToInject.entrySet())
167 | {
168 | map.put(entry.getKey(), entry.getValue());
169 | }
170 | }
171 |
172 | //------------------------------------------------------------------------------------------------------------------------------------------
173 | // Deswapping
174 | //-------------------------------------------------------------------------------------------------------------------------------------------
175 |
176 | private static void deswapLynxMotors(HardwareMap map)
177 | {
178 | //-----------------------------------------------------------------------------------
179 | // Motors: Lynx --> standard
180 | //-----------------------------------------------------------------------------------
181 |
182 | ArrayList> lynxMotorsToRecreateAsStandard = new ArrayList<>();
183 |
184 | for (Map.Entry entry : map.dcMotor.entrySet())
185 | {
186 | if (entry.getValue() instanceof ExpansionHubMotor)
187 | {
188 | lynxMotorsToRecreateAsStandard.add(entry);
189 | }
190 | }
191 |
192 | if (!lynxMotorsToRecreateAsStandard.isEmpty())
193 | {
194 | for (Map.Entry entry : lynxMotorsToRecreateAsStandard)
195 | {
196 | map.dcMotor.remove(entry.getKey());
197 | }
198 |
199 | for (Map.Entry entry : lynxMotorsToRecreateAsStandard)
200 | {
201 | map.dcMotor.put(entry.getKey(),
202 | new DcMotorImplEx(
203 | entry.getValue().getController(),
204 | entry.getValue().getPortNumber(),
205 | entry.getValue().getDirection(),
206 | entry.getValue().getMotorType()));
207 | }
208 | }
209 |
210 | }
211 |
212 | private static void deswapLynxServos(HardwareMap map)
213 | {
214 | //-----------------------------------------------------------------------------------
215 | // Servos: Lynx --> standard
216 | //-----------------------------------------------------------------------------------
217 |
218 | ArrayList> lynxServosToRecreateAsStandard = new ArrayList<>();
219 |
220 | for (Map.Entry entry : map.servo.entrySet())
221 | {
222 | if (entry.getValue() instanceof ExpansionHubServo)
223 | {
224 | lynxServosToRecreateAsStandard.add(entry);
225 | }
226 | }
227 |
228 | if (!lynxServosToRecreateAsStandard.isEmpty())
229 | {
230 | for (Map.Entry entry : lynxServosToRecreateAsStandard)
231 | {
232 | map.servo.remove(entry.getKey());
233 | }
234 |
235 | for (Map.Entry entry : lynxServosToRecreateAsStandard)
236 | {
237 | map.servo.put(entry.getKey(),
238 | new ServoImplEx(
239 | (ServoControllerEx) entry.getValue().getController(),
240 | entry.getValue().getPortNumber(),
241 | entry.getValue().getDirection(),
242 | ServoConfigurationType.getStandardServoType()));
243 | }
244 | }
245 | }
246 |
247 | private static void removeExpansionHubExForEachLynxModule(HardwareMap map)
248 | {
249 | //-----------------------------------------------------------------------------------
250 | // Remove ExpHbExs
251 | //-----------------------------------------------------------------------------------
252 |
253 | HashMap enhancedLynxModulesToRemove = new HashMap<>();
254 |
255 | for (ExpansionHubEx module : map.getAll(ExpansionHubEx.class))
256 | {
257 | enhancedLynxModulesToRemove.put(getHwMapName(module), module);
258 | }
259 |
260 | if (!enhancedLynxModulesToRemove.isEmpty())
261 | {
262 | for (Map.Entry entry : enhancedLynxModulesToRemove.entrySet())
263 | {
264 | map.remove(entry.getKey(), entry.getValue());
265 | }
266 | }
267 | }
268 |
269 | //------------------------------------------------------------------------------------------------------------------------------------------
270 | // Misc.
271 | //-------------------------------------------------------------------------------------------------------------------------------------------
272 |
273 | static String getHwMapName(HardwareDevice device)
274 | {
275 | return getHardwareMap().getNamesOf(device).iterator().next();
276 | }
277 |
278 | private static boolean hwMapContainsEnhancedModule(LynxModule module)
279 | {
280 | for(ExpansionHubEx enhancedModule : getHardwareMap().getAll(ExpansionHubEx.class))
281 | {
282 | //TODO: can we just replace with an '=='?
283 | if(module.getModuleAddress() == enhancedModule.getStandardModule().getModuleAddress())
284 | {
285 | return true;
286 | }
287 | }
288 |
289 | return false;
290 | }
291 |
292 | static LynxModule getLynxFromController(LynxController controller)
293 | {
294 | /*
295 | * NOTE: Historically we invoked the getModule() method
296 | * rather than grabbing the field directly. However, this
297 | * was reported to be causing problems in the wild because
298 | * getModule() actually returns a "PretendLynxModule" if
299 | * its internal "isHooked" boolean is false (as can happen
300 | * during a disconnect). This caused the cast to LynxModule
301 | * to fail and crashed the user code with an RE2Exception.
302 | *
303 | * See https://github.com/OpenFTC/RevExtensions2/issues/6
304 | */
305 |
306 | // We can get the underlying LynxModule object through a
307 | // LynxController object, but only through reflection.
308 | Field moduleField;
309 |
310 | try
311 | {
312 | // The "module" field is located within the LynxController class
313 | moduleField = LynxController.class.getDeclaredField("module");
314 |
315 | // Ensures the field is accessible for the next line. We still catch
316 | // the (impossible) IllegalAccessException just to be safe.
317 | moduleField.setAccessible(true);
318 |
319 | // Actually get the value from the controller that was passed in.
320 | return (LynxModule) moduleField.get(controller);
321 | }
322 | catch (Exception e)
323 | {
324 | throw new RE2Exception("Failed to reflect on LynxController! Please report this as an issue on the GitHub repository.");
325 | }
326 | }
327 | }
328 |
--------------------------------------------------------------------------------
/rev-extensions-2/src/main/java/org/openftc/revextensions2/VexMC29.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 OpenFTC Team
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in all
12 | * copies or substantial portions of the Software.
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | * SOFTWARE.
20 | */
21 | package org.openftc.revextensions2;
22 |
23 | import com.qualcomm.robotcore.hardware.ControlSystem;
24 | import com.qualcomm.robotcore.hardware.configuration.ServoFlavor;
25 | import com.qualcomm.robotcore.hardware.configuration.annotations.DeviceProperties;
26 | import com.qualcomm.robotcore.hardware.configuration.annotations.ServoType;
27 |
28 | /**
29 | * Support for the VEX Motor Controller 29
30 | *
31 | * To use an MC29, connect it to a servo port, then on the Robot Controller or
32 | * Driver Station, configure the port you connected it to as a VEX Motor Controller 29
33 | *
34 | */
35 | @ServoType(flavor = ServoFlavor.CONTINUOUS, usPulseLower = 1000, usPulseUpper = 2000)
36 | @DeviceProperties(xmlTag = "VexMC29", name = "VEX Motor Controller 29", description = "VEX Motor Controller 29", compatibleControlSystems = ControlSystem.REV_HUB)
37 | public interface VexMC29
38 | {
39 | }
40 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':rev-extensions-2', ':examples'
2 |
--------------------------------------------------------------------------------