Merge "Add more debug information to 2022 localizer"
diff --git a/package.json b/package.json
index 5d8775b..d16aed7 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,7 @@
     "@angular/compiler": "13.2.0",
     "@angular/compiler-cli": "13.2.0",
     "@angular/core": "13.2.0",
+    "@angular/forms": "13.2.0",
     "@angular/platform-browser": "13.2.0",
     "@angular/cli": "13.2.0",
     "@babel/cli": "^7.6.0",
diff --git a/scouting/scouting_test.ts b/scouting/scouting_test.ts
index 9ee9122..68dba52 100644
--- a/scouting/scouting_test.ts
+++ b/scouting/scouting_test.ts
@@ -27,6 +27,6 @@
 
   it('should display: This is an app.', async () => {
     await page.navigateTo();
-    expect(await page.getParagraphText()).toEqual('Auto');
+    expect(await page.getParagraphText()).toEqual('Team Selection');
   });
 });
diff --git a/scouting/webserver/requests/messages/submit_data_scouting.fbs b/scouting/webserver/requests/messages/submit_data_scouting.fbs
index 6213dd5..755e70b 100644
--- a/scouting/webserver/requests/messages/submit_data_scouting.fbs
+++ b/scouting/webserver/requests/messages/submit_data_scouting.fbs
@@ -9,7 +9,17 @@
     missed_shots_tele:int (id: 5);
     upper_goal_tele:int (id:6);
     lower_goal_tele:int (id:7);
+    // The rating that is used to rate the defense that this robot played on
+    // other robots.
+    // TODO: Document what the different values mean. E.g. 0 means no defense
+    // played?
     defense_rating:int (id:8);
+    // The amount of defense that other robots played on this robot.
+    // TODO: Document what the different values mean. E.g. 0 means no defense
+    // played against this robot?
+    defense_received_rating:int (id:10);
+    // The rating that this robot gets for its climbing.
+    // TODO: Change into an enum to make the different values self-documenting.
     climbing:int (id:9);
 }
 
diff --git a/scouting/www/app.ng.html b/scouting/www/app.ng.html
index d7c1b22..f763b7d 100644
--- a/scouting/www/app.ng.html
+++ b/scouting/www/app.ng.html
@@ -2,4 +2,4 @@
 <!--<div class="row">
   <h1 class="text-end">Match {{matchNumber}}, Team {{teamNumber}}</h1>
 </div>-->
-<app-entry></app-entry>
\ No newline at end of file
+<app-entry></app-entry>
diff --git a/scouting/www/app.ts b/scouting/www/app.ts
index c9d5ca1..f6247d3 100644
--- a/scouting/www/app.ts
+++ b/scouting/www/app.ts
@@ -5,6 +5,4 @@
   templateUrl: './app.ng.html',
 })
 export class App {
-  matchNumber: number = 1; //placeholder
-  teamNumber: number = 971; //placeholder
 }
diff --git a/scouting/www/entry/BUILD b/scouting/www/entry/BUILD
index 8f46de7..55b6937 100644
--- a/scouting/www/entry/BUILD
+++ b/scouting/www/entry/BUILD
@@ -14,7 +14,12 @@
     use_angular_plugin = True,
     visibility = ["//visibility:public"],
     deps = [
+        "//scouting/webserver/requests/messages:error_response_ts_fbs",
+        "//scouting/webserver/requests/messages:submit_data_scouting_response_ts_fbs",
+        "//scouting/webserver/requests/messages:submit_data_scouting_ts_fbs",
+        "@com_github_google_flatbuffers//ts:flatbuffers_ts",
         "@npm//@angular/common",
         "@npm//@angular/core",
+        "@npm//@angular/forms",
     ],
 )
diff --git a/scouting/www/entry/entry.component.css b/scouting/www/entry/entry.component.css
index 520b6d2..2cb500f 100644
--- a/scouting/www/entry/entry.component.css
+++ b/scouting/www/entry/entry.component.css
@@ -1,8 +1,24 @@
 * {
-    margin: 10px;
+    padding: 10px;
+}
+
+.center-column {
+  display: flex;
+  align-items: stretch;
+  flex-direction: column;
+  text-align: center;
+}
+
+.buttons {
+  display: flex;
+  justify-content: space-between;
 }
 
 textarea {
     width: 300px;
     height: 150px;
-}
\ No newline at end of file
+}
+
+.error_message {
+    color: red;
+}
diff --git a/scouting/www/entry/entry.component.ts b/scouting/www/entry/entry.component.ts
index 21bdac4..ddc31df 100644
--- a/scouting/www/entry/entry.component.ts
+++ b/scouting/www/entry/entry.component.ts
@@ -1,6 +1,15 @@
 import { Component, OnInit } from '@angular/core';
 
-type Section = 'Auto'|'TeleOp'|'Climb'|'Defense'|'Review and Submit'|'Home'
+import * as flatbuffer_builder from 'org_frc971/external/com_github_google_flatbuffers/ts/builder';
+import {ByteBuffer} from 'org_frc971/external/com_github_google_flatbuffers/ts/byte-buffer';
+import * as error_response from 'org_frc971/scouting/webserver/requests/messages/error_response_generated';
+import * as submit_data_scouting_response from 'org_frc971/scouting/webserver/requests/messages/submit_data_scouting_response_generated';
+import * as submit_data_scouting from 'org_frc971/scouting/webserver/requests/messages/submit_data_scouting_generated';
+import SubmitDataScouting = submit_data_scouting.scouting.webserver.requests.SubmitDataScouting;
+import SubmitDataScoutingResponse = submit_data_scouting_response.scouting.webserver.requests.SubmitDataScoutingResponse;
+import ErrorResponse = error_response.scouting.webserver.requests.ErrorResponse;
+
+type Section = 'Team Selection'|'Auto'|'TeleOp'|'Climb'|'Defense'|'Review and Submit'|'Home'
 type Level = 'Low'|'Medium'|'High'|'Transversal'
 
 @Component({
@@ -9,18 +18,21 @@
     styleUrls: ['./entry.component.css']
 })
 export class EntryComponent {
-    section: Section = 'Auto'; //placeholder
+    section: Section = 'Team Selection';
+    matchNumber: number = 1
+    teamNumber: number = 1
     autoUpperShotsMade: number = 0;
     autoLowerShotsMade: number = 0;
     autoShotsMissed: number = 0;
     teleUpperShotsMade: number = 0;
     teleLowerShotsMade: number = 0;
     teleShotsMissed: number = 0;
-    defensePlayedOnScore: number = 50;
-    defensePlayedScore: number = 50;
+    defensePlayedOnScore: number = 3;
+    defensePlayedScore: number = 3;
     level: Level;
     proper: boolean = false;
     climbed: boolean = false;
+    errorMessage: string = '';
 
     toggleProper() {
         this.proper = !this.proper;
@@ -59,7 +71,9 @@
     }
 
     nextSection() {
-        if (this.section === 'Auto') {
+        if (this.section === 'Team Selection') {
+            this.section = 'Auto';
+        } else if (this.section === 'Auto') {
             this.section = 'TeleOp';
         } else if (this.section === 'TeleOp') {
             this.section = 'Climb';
@@ -68,10 +82,24 @@
         } else if (this.section === 'Defense') {
             this.section = 'Review and Submit';
         } else if (this.section === 'Review and Submit') {
-            this.section = 'Home';
+            this.submitDataScouting();
         }
     }
 
+    prevSection() {
+      if (this.section === 'Auto') {
+        this.section = 'Team Selection';
+      } else if (this.section === 'TeleOp') {
+        this.section = 'Auto';
+      } else if (this.section === 'Climb') {
+        this.section = 'TeleOp';
+      } else if (this.section === 'Defense') {
+        this.section = 'Climb';
+      } else if (this.section === 'Review and Submit') {
+        this.section = 'Defense';
+      }
+    }
+
     adjustAutoUpper(by: number) {
         this.autoUpperShotsMade = Math.max(0, this.autoUpperShotsMade + by);
     }
@@ -95,4 +123,39 @@
     adjustTeleMissed(by: number) {
         this.teleShotsMissed = Math.max(0, this.teleShotsMissed + by);
     }
+
+    async submitDataScouting() {
+        const builder = new flatbuffer_builder.Builder() as unknown as flatbuffers.Builder;
+        SubmitDataScouting.startSubmitDataScouting(builder);
+        SubmitDataScouting.addTeam(builder, this.teamNumber);
+        SubmitDataScouting.addMatch(builder, this.matchNumber);
+        SubmitDataScouting.addMissedShotsAuto(builder, this.autoShotsMissed);
+        SubmitDataScouting.addUpperGoalAuto(builder, this.autoUpperShotsMade);
+        SubmitDataScouting.addLowerGoalAuto(builder, this.autoLowerShotsMade);
+        SubmitDataScouting.addMissedShotsTele(builder, this.teleShotsMissed);
+        SubmitDataScouting.addUpperGoalTele(builder, this.teleUpperShotsMade);
+        SubmitDataScouting.addLowerGoalTele(builder, this.teleLowerShotsMade);
+        SubmitDataScouting.addDefenseRating(builder, this.defensePlayedScore);
+        // TODO(phil): Add support for defensePlayedOnScore.
+        // TODO(phil): Fix the Climbing score.
+        SubmitDataScouting.addClimbing(builder, 1);
+        builder.finish(SubmitDataScouting.endSubmitDataScouting(builder));
+
+        const buffer = builder.asUint8Array();
+        const res = await fetch(
+            '/requests/submit/data_scouting', {method: 'POST', body: buffer});
+
+        if (res.ok) {
+            // We successfully submitted the data. Go back to Home.
+            this.section = 'Home';
+        } else {
+            const resBuffer = await res.arrayBuffer();
+            const fbBuffer = new ByteBuffer(new Uint8Array(resBuffer));
+            const parsedResponse = ErrorResponse.getRootAsErrorResponse(
+                fbBuffer as unknown as flatbuffers.ByteBuffer);
+
+            const errorMessage = parsedResponse.errorMessage();
+            this.errorMessage = `Received ${res.status} ${res.statusText}: "${errorMessage}"`;
+        }
+    }
 }
diff --git a/scouting/www/entry/entry.module.ts b/scouting/www/entry/entry.module.ts
index d454c2e..35ecd26 100644
--- a/scouting/www/entry/entry.module.ts
+++ b/scouting/www/entry/entry.module.ts
@@ -1,11 +1,12 @@
 import {NgModule} from '@angular/core';
 import {CommonModule} from '@angular/common';
 import {EntryComponent} from './entry.component';
+import {FormsModule} from '@angular/forms';
 
 @NgModule({
   declarations: [EntryComponent],
   exports: [EntryComponent],
-  imports: [CommonModule],
+  imports: [CommonModule, FormsModule],
 })
 export class EntryModule {
 }
diff --git a/scouting/www/entry/entry.ng.html b/scouting/www/entry/entry.ng.html
index c20edf9..e52e6bc 100644
--- a/scouting/www/entry/entry.ng.html
+++ b/scouting/www/entry/entry.ng.html
@@ -3,6 +3,20 @@
 </div>
 
 <ng-container [ngSwitch]="section">
+    <div *ngSwitchCase="'Team Selection'" id="team_selection" class="container-fluid">
+        <div class="row">
+            <label for="match_number">Match Number</label>
+            <input [(ngModel)]="matchNumber" type="number" id="match_number" min="1" max="999">
+        </div>
+        <div class="row">
+            <label for="team_number">Team Number</label>
+            <input [(ngModel)]="teamNumber" type="number" id="team_number" min="1" max="9999">
+        </div>
+        <div class="text-right">
+            <button class="btn btn-primary" (click)="nextSection()">Next</button>
+        </div>
+    </div>
+
     <div *ngSwitchCase="'Auto'" id="auto" class="container-fluid">
         <div class="row">
             <!--Image here-->
@@ -30,57 +44,60 @@
             </form>
         </div>
         <div class="row justify-content-center">
-            <div class="col-sm">
-                <h4>Upper Shots Made</h4>
-                <button (click)="adjustAutoUpper(1)" class="btn btn-secondary">+</button>
+            <span class="col-4 center-column">
+                <h4>Upper</h4>
+                <button (click)="adjustAutoUpper(1)" class="btn btn-secondary btn-block">+</button>
                 <h3>{{autoUpperShotsMade}}</h3>
-                <button (click)="adjustAutoUpper(-1)" class="btn btn-secondary">-</button>
-            </div>
+                <button (click)="adjustAutoUpper(-1)" class="btn btn-secondary btn-block">-</button>
+            </span>
 
-            <div class="col-sm">
-                <h4>Lower Shots Made</h4>
-                <button (click)="adjustAutoLower(1)" class="col-xs btn btn-secondary">+</button>
+            <span class="col-4 center-column">
+                <h4>Lower</h4>
+                <button (click)="adjustAutoLower(1)" class="btn btn-secondary btn-block">+</button>
                 <h3>{{autoLowerShotsMade}}</h3>
-                <button (click)="adjustAutoLower(-1)" class="btn btn-secondary">-</button>
-            </div>
+                <button (click)="adjustAutoLower(-1)" class="btn btn-secondary btn-block">-</button>
+            </span>
 
-            <div class="col-sm">
-                <h4>Missed Shots</h4>
-                <button (click)="adjustAutoMissed(1)" class="btn btn-secondary">+</button>
+            <span class="col-4 center-column">
+                <h4>Missed</h4>
+                <button (click)="adjustAutoMissed(1)" class="btn btn-secondary btn-block">+</button>
                 <h3>{{autoShotsMissed}}</h3>
-                <button (click)="adjustAutoMissed(-1)" class="btn btn-secondary">-</button>
-            </div>
+                <button (click)="adjustAutoMissed(-1)" class="btn btn-secondary btn-block">-</button>
+            </span>
         </div>
-        <div class="text-right">
-            <button class="btn btn-primary" (click)="nextSection()">Next</button>
+        <div class="buttons">
+          <!-- hack to right align the next button -->
+          <div></div>
+          <button class="btn btn-primary" (click)="nextSection()">Next</button>
         </div>
     </div>
 
     <div *ngSwitchCase="'TeleOp'" id="teleop" class="container-fluid">
         <div class="row justify-content-center">
-            <div class="col-sm">
-                <h4>Upper Shots Made</h4>
-                <button (click)="adjustTeleUpper(1)" class="btn btn-secondary">+</button>
+            <span class="col-4 center-column">
+                <h4>Upper</h4>
+                <button (click)="adjustTeleUpper(1)" class="btn btn-secondary btn-block">+</button>
                 <h3>{{teleUpperShotsMade}}</h3>
-                <button (click)="adjustTeleUpper(-1)" class="btn btn-secondary">-</button>
-            </div>
+                <button (click)="adjustTeleUpper(-1)" class="btn btn-secondary btn-block">-</button>
+            </span>
 
-            <div class="col-sm">
-                <h4>Lower Shots Made</h4>
-                <button (click)="adjustTeleLower(1)" class="btn btn-secondary">+</button>
+            <span class="col-4 center-column">
+                <h4>Lower</h4>
+                <button (click)="adjustTeleLower(1)" class="btn btn-secondary btn-block">+</button>
                 <h3>{{teleLowerShotsMade}}</h3>
-                <button (click)="adjustTeleLower(-1)" class="btn btn-secondary">-</button>
-            </div>
+                <button (click)="adjustTeleLower(-1)" class="btn btn-secondary btn-block">-</button>
+            </span>
 
-            <div class="col-sm">
-                <h4>Missed Shots</h4>
-                <button (click)="adjustTeleMissed(1)" class="btn btn-secondary">+</button>
+            <span class="col-4 center-column">
+                <h4>Missed</h4>
+                <button (click)="adjustTeleMissed(1)" class="btn btn-secondary btn-block">+</button>
                 <h3>{{teleShotsMissed}}</h3>
-                <button (click)="adjustTeleMissed(-1)" class="btn btn-secondary">-</button>
-            </div>
+                <button (click)="adjustTeleMissed(-1)" class="btn btn-secondary btn-block">-</button>
+            </span>
         </div>
-        <div class="text-right">
-            <button class="btn btn-primary" (click)="nextSection()">Next</button>
+        <div class="buttons">
+          <button class="btn btn-primary" (click)="prevSection()">Back</button>
+          <button class="btn btn-primary" (click)="nextSection()">Next</button>
         </div>
     </div>
 
@@ -105,7 +122,10 @@
             <h4>Comments</h4>
             <textarea></textarea>
         </div>
-        <button class="btn btn-primary" (click)="nextSection()">Next</button>
+        <div class="buttons">
+          <button class="btn btn-primary" (click)="prevSection()">Back</button>
+          <button class="btn btn-primary" (click)="nextSection()">Next</button>
+        </div>
     </div>
 
     <div *ngSwitchCase="'Defense'" id="defense" class="container-fluid">
@@ -117,7 +137,7 @@
             </div>
 
             <div class="col">
-                <input type="range" min="1" max="100" value="50" (input)="defensePlayedOnSlider($event)">
+                <input type="range" min="1" max="5" value="3" (input)="defensePlayedOnSlider($event)">
             </div>
 
             <div class="col">
@@ -136,7 +156,7 @@
             </div>
 
             <div class="col">
-                <input type="range" min="1" max="100" value="50" (input)="defensePlayedSlider($event)">
+                <input type="range" min="1" max="5" value="3" (input)="defensePlayedSlider($event)">
             </div>
 
             <div class="col">
@@ -145,10 +165,19 @@
         </div>
         <h6 class="text-center">{{defensePlayedScore}}</h6>
 
-        <button class="btn btn-primary" (click)="nextSection()">Next</button>
+        <div class="buttons">
+          <button class="btn btn-primary" (click)="prevSection()">Back</button>
+          <button class="btn btn-primary" (click)="nextSection()">Next</button>
+        </div>
     </div>
 
     <div *ngSwitchCase="'Review and Submit'" id="review" class="container-fluid">
+        <h4>Team Selection</h4>
+        <ul>
+            <li>Match number: {{matchNumber}}</li>
+            <li>Team number: {{teamNumber}}</li>
+        </ul>
+
         <h4>Auto</h4>
         <ul>
             <li>Upper Shots Made: {{autoUpperShotsMade}}</li>
@@ -180,6 +209,11 @@
             <li>Defense Played Raing: {{defensePlayedScore}}</li>
         </ul>
 
-        <button class="btn btn-primary" (click)="nextSection()">Submit</button>
+        <div class="error_message">{{ errorMessage }}</div>
+
+        <div class="buttons">
+          <button class="btn btn-primary" (click)="prevSection()">Back</button>
+          <button class="btn btn-primary" (click)="nextSection()">Submit</button>
+        </div>
     </div>
 </ng-container>
diff --git a/y2022/wpilib_interface.cc b/y2022/wpilib_interface.cc
index acc9fdd..24f8323 100644
--- a/y2022/wpilib_interface.cc
+++ b/y2022/wpilib_interface.cc
@@ -658,8 +658,8 @@
     sensor_reader.set_catapult_potentiometer(
         std::make_unique<frc::AnalogInput>(2));
 
-    sensor_reader.set_heading_input(make_unique<frc::DigitalInput>(8));
-    sensor_reader.set_yaw_rate_input(make_unique<frc::DigitalInput>(9));
+    sensor_reader.set_heading_input(make_unique<frc::DigitalInput>(9));
+    sensor_reader.set_yaw_rate_input(make_unique<frc::DigitalInput>(8));
 
     AddLoop(&sensor_reader_event_loop);
 
diff --git a/yarn.lock b/yarn.lock
index a20b10c..e76092f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -103,6 +103,13 @@
   dependencies:
     tslib "^2.3.0"
 
+"@angular/forms@13.2.0":
+  version "13.2.0"
+  resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-13.2.0.tgz#67d505c09175d1ba809be721303316db7b0c60d4"
+  integrity sha512-aduXLuvqynDRRdb316yY1O5rdMQ2DKeNxu5P2FG1nkLQ3hqZvpiaUMhFyXvKDG3s0rV5e/PZs1cpg0Aqdfwevw==
+  dependencies:
+    tslib "^2.3.0"
+
 "@angular/platform-browser@13.2.0":
   version "13.2.0"
   resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-13.2.0.tgz#d8a309c231dec646ab1dad28240466a00151b54b"