1 /***************************************************************************
2     Process Outputs.
3 
4     - Only the Deluxe Moving Motor Code is ported for now.
5     - This is used by the force-feedback haptic system.
6 
7     One thing to note is that this code was originally intended to drive
8     a moving hydraulic cabinet, not to be mapped to a haptic device.
9 
10     Therefore, it's not perfect when used in this way, but the results
11     aren't bad :)
12 
13     Copyright Chris White.
14     See license.txt for more details.
15 ***************************************************************************/
16 
17 #pragma once
18 
19 #include "stdint.hpp"
20 
21 struct CoinChute
22 {
23     // Coin Chute Counters
24     uint8_t counter[3];
25     // Output bit
26     uint8_t output_bit;
27 };
28 
29 class OOutputs
30 {
31 public:
32     const static int MODE_DISABLED = 0; // Disabled
33     const static int MODE_CABINET = 1; // SmartyPi Interface / Original Cabinet
34     const static int MODE_FFEEDBACK = 2; // Force Feedback for Wheels
35     const static int MODE_RUMBLE = 3; // Simple rumble for controllers
36 
37     // Hardware Motor Control:
38     // 0 = Switch off
39     // 5 = Left
40     // 8 = Centre
41     // B = Right
42     uint8_t hw_motor_control;
43 
44     // Digital Outputs
45     enum
46     {
47         D_EXT_MUTE   = 0x01, // bit 0 = External Amplifier Mute Control
48         D_BRAKE_LAMP = 0x02, // bit 1 = brake lamp
49         D_START_LAMP = 0x04, // bit 2 = start lamp
50         D_COIN1_SUCC = 0x08, // bit 3 = Coin successfully inserted - Chute 2
51         D_COIN2_SUCC = 0x10, // bit 4 = Coin successfully inserted - Chute 1
52         D_MOTOR      = 0x20, // bit 5 = steering wheel central vibration
53         D_UNUSED     = 0x40, // bit 6 = ?
54         D_SOUND      = 0x80, // bit 7 = sound enable
55     };
56 
57     CoinChute chute1, chute2;
58 
59     OOutputs(void);
60     ~OOutputs(void);
61 
62     void init();
63     void set_mode(int);
64     bool diag_motor(int16_t input_motor, uint8_t hw_motor_limit, uint32_t packets);
65     bool calibrate_motor(int16_t input_motor, uint8_t hw_motor_limit, uint32_t packets);
66     void tick(int16_t input_motor = 0);
67     void writeDigitalToConsole();
68     void set_digital(uint8_t);
69     void clear_digital(uint8_t);
70     int is_set(uint8_t);
71     void coin_chute_out(CoinChute* chute, bool insert);
72 
73 private:
74     int mode;
75 
76     uint8_t dig_out, dig_out_old;
77 
78     const static uint16_t STATE_INIT   = 0;
79     const static uint16_t STATE_DELAY  = 1;
80     const static uint16_t STATE_LEFT   = 2;
81     const static uint16_t STATE_RIGHT  = 3;
82     const static uint16_t STATE_CENTRE = 4;
83     const static uint16_t STATE_DONE   = 5;
84     const static uint16_t STATE_EXIT   = 6;
85 
86     // Calibration Counter
87     const static int COUNTER_RESET = 300;
88 
89     const static uint8_t MOTOR_OFF    = 0;
90     const static uint8_t MOTOR_RIGHT  = 0x5;
91     const static uint8_t MOTOR_CENTRE = 0x8;
92     const static uint8_t MOTOR_LEFT   = 0xB;
93 
94 
95     // These are calculated during startup in the original game.
96     // Here we just hardcode them, as the motor init code isn't ported.
97     const static uint8_t CENTRE_POS    = 0x80;
98     const static uint8_t LEFT_LIMIT    = 0xC1;
99     const static uint8_t RIGHT_LIMIT   = 0x3C;
100 
101     // Motor Limit Values. Calibrated during startup.
102     int16_t limit_left;
103     int16_t limit_right;
104 
105     // Motor Centre Position. (We Fudge this for Force Feedback wheel mode.)
106     int16_t motor_centre_pos;
107 
108     // Difference between input_motor and input_motor_old
109     int16_t motor_x_change;
110 
111     uint16_t motor_state;
112     bool motor_enabled;
113 
114     // 0x11: Motor Control Value
115     int8_t motor_control;
116     // 0x12: Movement (1 = Left, -1 = Right, 0 = None)
117     int8_t motor_movement;
118     // 0x14: Is Motor Centered
119     bool is_centered;
120     // 0x16: Motor X Change Latch
121     int16_t motor_change_latch;
122     // 0x18: Speed
123     int16_t speed;
124     // 0x1A: Road Curve
125     int16_t curve;
126     // 0x1E: Increment counter to index motor table for off-road/crash
127     int16_t vibrate_counter;
128     // 0x20: Last Motor X_Change > 8. No need to adjust further.
129     bool was_small_change;
130     // 0x22: Adjusted movement value based on steering 1
131     int16_t movement_adjust1;
132     // 0x24: Adjusted movement value based on steering 2
133     int16_t movement_adjust2;
134     // 0x26: Adjusted movement value based on steering 3
135     int16_t movement_adjust3;
136 
137     // Counter control for motor tests
138     int16_t counter;
139 
140     // Columns for output
141     uint16_t col1, col2;
142 
143     void diag_left(int16_t input_motor, uint8_t hw_motor_limit);
144     void diag_right(int16_t input_motor, uint8_t hw_motor_limit);
145     void diag_centre(int16_t input_motor, uint8_t hw_motor_limit);
146     void diag_done();
147 
148     void calibrate_left(int16_t input_motor, uint8_t hw_motor_limit);
149     void calibrate_right(int16_t input_motor, uint8_t hw_motor_limit);
150     void calibrate_centre(int16_t input_motor, uint8_t hw_motor_limit);
151     void calibrate_done();
152 
153     void do_motors(const int MODE, int16_t input_motor);
154     void car_moving(const int MODE);
155     void car_stationary();
156     void adjust_motor();
157     void do_motor_crash();
158     void do_motor_offroad();
159     void set_value(const uint8_t*, uint8_t);
160     void done();
161     void motor_output(uint8_t cmd);
162 
163     void do_vibrate_upright();
164     void do_vibrate_mini();
165 };