2727#define MSG_SUBARU_Wheel_Speeds 0x13a
2828
2929#define MSG_SUBARU_ES_LKAS 0x122
30+ #define MSG_SUBARU_ES_LKAS_ANGLE 0x124
3031#define MSG_SUBARU_ES_Brake 0x220
3132#define MSG_SUBARU_ES_Distance 0x221
3233#define MSG_SUBARU_ES_Status 0x222
7071
7172static bool subaru_gen2 = false;
7273static bool subaru_longitudinal = false;
74+ static bool subaru_lkas_angle = false;
7375
7476static uint32_t subaru_get_checksum (const CANPacket_t * to_push ) {
7577 return (uint8_t )GET_BYTE (to_push , 0 );
@@ -91,7 +93,8 @@ static uint32_t subaru_compute_checksum(const CANPacket_t *to_push) {
9193
9294static void subaru_rx_hook (const CANPacket_t * to_push ) {
9395 const int bus = GET_BUS (to_push );
94- const int alt_main_bus = subaru_gen2 ? SUBARU_ALT_BUS : SUBARU_MAIN_BUS ;
96+ const int alt_main_bus = (subaru_gen2 || subaru_lkas_angle ) ? SUBARU_ALT_BUS : SUBARU_MAIN_BUS ;
97+ const int stock_lkas_msg = subaru_lkas_angle ? MSG_SUBARU_ES_LKAS_ANGLE : MSG_SUBARU_ES_LKAS ;
9598
9699 int addr = GET_ADDR (to_push );
97100 if ((addr == MSG_SUBARU_Steering_Torque ) && (bus == SUBARU_MAIN_BUS )) {
@@ -107,9 +110,16 @@ static void subaru_rx_hook(const CANPacket_t *to_push) {
107110 }
108111
109112 // enter controls on rising edge of ACC, exit controls on ACC off
110- if ((addr == MSG_SUBARU_CruiseControl ) && (bus == alt_main_bus )) {
111- bool cruise_engaged = GET_BIT (to_push , 41U );
112- pcm_cruise_check (cruise_engaged );
113+ if (subaru_lkas_angle ) {
114+ if ((addr == MSG_SUBARU_ES_DashStatus ) && (bus == SUBARU_CAM_BUS )) {
115+ bool cruise_engaged = GET_BIT (to_push , 36U );
116+ pcm_cruise_check (cruise_engaged );
117+ }
118+ } else {
119+ if ((addr == MSG_SUBARU_CruiseControl ) && (bus == alt_main_bus )) {
120+ bool cruise_engaged = GET_BIT (to_push , 41U );
121+ pcm_cruise_check (cruise_engaged );
122+ }
113123 }
114124
115125 // update vehicle moving with any non-zero wheel speed
@@ -132,13 +142,25 @@ static void subaru_rx_hook(const CANPacket_t *to_push) {
132142 gas_pressed = GET_BYTE (to_push , 4 ) != 0U ;
133143 }
134144
135- generic_rx_checks ((addr == MSG_SUBARU_ES_LKAS ) && (bus == SUBARU_MAIN_BUS ));
145+ generic_rx_checks ((addr == stock_lkas_msg ) && (bus == SUBARU_MAIN_BUS ));
136146}
137147
138148static bool subaru_tx_hook (const CANPacket_t * to_send ) {
139149 const SteeringLimits SUBARU_STEERING_LIMITS = SUBARU_STEERING_LIMITS_GENERATOR (2047 , 50 , 70 );
140150 const SteeringLimits SUBARU_GEN2_STEERING_LIMITS = SUBARU_STEERING_LIMITS_GENERATOR (1000 , 40 , 40 );
141151
152+ const SteeringLimits SUBARU_ANGLE_STEERING_LIMITS = {
153+ .angle_deg_to_can = 100. ,
154+ .angle_rate_up_lookup = {
155+ {0. , 15. , 15. },
156+ {5. , .8 , .8 }
157+ },
158+ .angle_rate_down_lookup = {
159+ {0. , 15. , 15. },
160+ {5. , .4 , .4 }
161+ },
162+ };
163+
142164 const LongitudinalLimits SUBARU_LONG_LIMITS = {
143165 .min_gas = 808 , // appears to be engine braking
144166 .max_gas = 3400 , // approx 2 m/s^2 when maxing cruise_rpm and cruise_throttle
@@ -164,6 +186,14 @@ static bool subaru_tx_hook(const CANPacket_t *to_send) {
164186 violation |= steer_torque_cmd_checks (desired_torque , steer_req , limits );
165187 }
166188
189+ if (addr == MSG_SUBARU_ES_LKAS_ANGLE ) {
190+ int desired_angle = GET_BYTES (to_send , 5 , 3 ) & 0x1FFFFU ;
191+ desired_angle = -1 * to_signed (desired_angle , 17 );
192+ bool lkas_request = GET_BIT (to_send , 12U );
193+
194+ violation |= steer_angle_cmd_checks (desired_angle , lkas_request , SUBARU_ANGLE_STEERING_LIMITS );
195+ }
196+
167197 // check es_brake brake_pressure limits
168198 if (addr == MSG_SUBARU_ES_Brake ) {
169199 int es_brake_pressure = GET_BYTES (to_send , 2 , 2 );
@@ -210,13 +240,15 @@ static bool subaru_tx_hook(const CANPacket_t *to_send) {
210240static int subaru_fwd_hook (int bus_num , int addr ) {
211241 int bus_fwd = -1 ;
212242
243+ const int stock_lkas_msg = subaru_lkas_angle ? MSG_SUBARU_ES_LKAS_ANGLE : MSG_SUBARU_ES_LKAS ;
244+
213245 if (bus_num == SUBARU_MAIN_BUS ) {
214246 bus_fwd = SUBARU_CAM_BUS ; // to the eyesight camera
215247 }
216248
217249 if (bus_num == SUBARU_CAM_BUS ) {
218250 // Global platform
219- bool block_lkas = ((addr == MSG_SUBARU_ES_LKAS ) ||
251+ bool block_lkas = ((addr == stock_lkas_msg ) ||
220252 (addr == MSG_SUBARU_ES_DashStatus ) ||
221253 (addr == MSG_SUBARU_ES_LKAS_State ) ||
222254 (addr == MSG_SUBARU_ES_Infotainment ));
@@ -254,6 +286,11 @@ static safety_config subaru_init(uint16_t param) {
254286 SUBARU_GEN2_LONG_ADDITIONAL_TX_MSGS ()
255287 };
256288
289+ static const CanMsg SUBARU_LKAS_ANGLE_TX_MSGS [] = {
290+ SUBARU_COMMON_TX_MSGS (SUBARU_ALT_BUS , MSG_SUBARU_ES_LKAS_ANGLE )
291+ SUBARU_COMMON_TX_MSGS (SUBARU_ALT_BUS , MSG_SUBARU_ES_LKAS )
292+ };
293+
257294 static RxCheck subaru_rx_checks [] = {
258295 SUBARU_COMMON_RX_CHECKS (SUBARU_MAIN_BUS )
259296 };
@@ -263,16 +300,20 @@ static safety_config subaru_init(uint16_t param) {
263300 };
264301
265302 const uint16_t SUBARU_PARAM_GEN2 = 1 ;
303+ const uint16_t SUBARU_PARAM_LONGITUDINAL = 2 ;
304+ const uint16_t SUBARU_PARAM_LKAS_ANGLE = 8 ;
266305
267306 subaru_gen2 = GET_FLAG (param , SUBARU_PARAM_GEN2 );
307+ subaru_lkas_angle = GET_FLAG (param , SUBARU_PARAM_LKAS_ANGLE );
268308
269309#ifdef ALLOW_DEBUG
270- const uint16_t SUBARU_PARAM_LONGITUDINAL = 2 ;
271310 subaru_longitudinal = GET_FLAG (param , SUBARU_PARAM_LONGITUDINAL );
272311#endif
273312
274313 safety_config ret ;
275- if (subaru_gen2 ) {
314+ if (subaru_lkas_angle ) {
315+ ret = BUILD_SAFETY_CFG (subaru_gen2_rx_checks , SUBARU_LKAS_ANGLE_TX_MSGS );
316+ } else if (subaru_gen2 ) {
276317 ret = subaru_longitudinal ? BUILD_SAFETY_CFG (subaru_gen2_rx_checks , SUBARU_GEN2_LONG_TX_MSGS ) : \
277318 BUILD_SAFETY_CFG (subaru_gen2_rx_checks , SUBARU_GEN2_TX_MSGS );
278319 } else {
0 commit comments