#include <ESP32Servo.h>
#include <Preferences.h>
#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsServer.h>

const char* AP_SSID = "Crenux-Truck";
const char* AP_PASS = "MyCrenuxTruck";

WebServer server(80);
WebSocketsServer webSocket(81);

Servo steering;
Servo tractionMotor;

const int motorPin = 12;
const int steerPin = 13;
const int leftEndstop = 14;
const int rightEndstop = 22;
const int headL = 15, headR = 2;
const int turnL = 4, turnR = 16;
const int polR1 = 17, polR2 = 5, polB1 = 19, polB2 = 21;
const int buzz = 18;

Preferences pref;
bool fw = false, bw = false, left = false, right = false;
bool eng = false, park = true, light = false;
bool haz = false, pol = false, horn = false;
String mode = "Eco";
float power = 0, tpower = 0;
unsigned long t = 0, tHaz = 0, tPol = 0, tRev = 0, tInd = 0;
int pStep = 0;
bool hState = false, iState = false;

const unsigned long CMD_TIMEOUT = 300;
unsigned long lastFwCmd = 0, lastBwCmd = 0, lastLeftCmd = 0, lastRightCmd = 0;

void refreshCmdTimeout(){
  unsigned long n = millis();
  if(fw    && n - lastFwCmd    > CMD_TIMEOUT) fw    = false;
  if(bw    && n - lastBwCmd    > CMD_TIMEOUT) bw    = false;
  if(left  && n - lastLeftCmd  > CMD_TIMEOUT) left  = false;
  if(right && n - lastRightCmd > CMD_TIMEOUT) right = false;
}

const char HTML[] PROGMEM = R"rawliteral(
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Truck</title>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{background:#000;color:#fff;font-family:Arial,sans-serif;height:100vh;display:flex;align-items:center;justify-content:center;touch-action:manipulation;padding:8px}
#c{width:100%;max-width:400px;background:#111;border-radius:24px;padding:16px;border:1px solid #222}
.r{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}
.logo{font-size:10px;color:#555;letter-spacing:2px}
#s{font-size:9px;padding:4px 8px;border-radius:12px;background:#1a1a1a;color:#666}
#s.ok{color:#0f0;background:#020}
.sp{text-align:center;margin:10px 0}
#v{font-size:90px;font-weight:900;line-height:1}
#u{font-size:11px;color:#555;letter-spacing:3px}
#g{display:inline-block;font-size:40px;font-weight:900;padding:4px 20px;border-radius:12px;background:#1a1a1a;margin:8px 0}
#g.D{color:#0f0}#g.R{color:#f00}#g.P{color:#fa0}#g.N{color:#888}
.dp{display:grid;grid-template-columns:1fr 1fr 1fr;grid-template-rows:1fr 1fr 1fr;gap:5px;width:160px;height:160px;margin:8px auto}
.db{border:none;border-radius:14px;background:#1a1a1a;color:#555;font-size:20px;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center}
.db:active{background:#333}
.u{grid-column:2;grid-row:1}.l{grid-column:1;grid-row:2}.m{grid-column:2;grid-row:2;font-size:10px}.r2{grid-column:3;grid-row:2}.d{grid-column:2;grid-row:3}
.u.on,.d.on{background:#050;color:#0f0}.l.on,.r2.on{background:#004;color:#0af}
.md{display:flex;gap:4px;margin:8px 0}
.mb{flex:1;padding:8px;border-radius:10px;border:1px solid #222;background:#111;color:#555;font-size:9px;font-weight:700;cursor:pointer}
.mb:active{transform:scale(.95)}
.mb.a{color:#fff;border-color:#444}
.mb.eco.a{color:#0f0;border-color:#0f0;background:#020}
.mb.comf.a{color:#0af;border-color:#0af;background:#012}
.mb.sport.a{color:#f00;border-color:#f00;background:#200}
.mb.race.a{color:#f44;border-color:#f44;background:#300}
.g2{display:grid;grid-template-columns:1fr 1fr;gap:5px;margin:6px 0}
.bt{padding:12px;border-radius:12px;border:1px solid #222;background:#1a1a1a;color:#666;font-size:11px;font-weight:600;cursor:pointer;min-height:42px}
.bt:active{transform:scale(.96)}
.bt.on{color:#fff}
.bt.eng.on{background:#0a0;color:#000;border-color:#0f0}
.bt.prk{color:#fa0;border-color:#420}
.bt.prk.on{background:#420;border-color:#fa0}
.bt.lgt.on{background:#023;border-color:#08f;color:#08f}
.bt.pol.on{background:#300;border-color:#f00;color:#f00;animation:pb .5s infinite}
@keyframes pb{0%,100%{opacity:1}50%{opacity:.4}}
.ar{display:flex;justify-content:center;gap:12px;margin:6px 0}
.ab{width:40px;height:40px;border-radius:50%;border:1.5px solid #222;background:#1a1a1a;color:#555;font-size:14px;cursor:pointer;display:flex;align-items:center;justify-content:center}
.ab:active{transform:scale(.9)}
.ab.on{color:#0f0;border-color:#0f0;background:#020;animation:ib .7s infinite}
@keyframes ib{0%,49%{opacity:1}50%,100%{opacity:.3}}
.ab.hz{font-size:12px;font-weight:900}
.ab.hz.on{color:#f00;border-color:#f00;background:#300;animation:hb .7s infinite}
@keyframes hb{0%,49%{opacity:1}50%,100%{opacity:.2}}
.inf{display:flex;justify-content:space-around;padding-top:8px;border-top:1px solid #1a1a1a;font-size:8px;color:#555}
.inf b{color:#aaa;font-size:12px}
</style></head><body>
<div id="c">
<div class="r"><span class="logo">MERCEDES-BENZ</span><span id="s">Offline</span></div>
<div class="sp"><div id="v">0</div><div id="u">KM/H</div></div>
<div style="text-align:center"><div id="g">P</div></div>
<div class="dp">
<button class="db u" id="bu" onmousedown="go('F')" onmouseup="stop('f')" onmouseleave="stop('f')" ontouchstart="event.preventDefault();go('F')" ontouchend="event.preventDefault();stop('f')" ontouchcancel="event.preventDefault();stop('f')">▲</button>
<button class="db l" id="bl" onmousedown="go('L')" onmouseup="stop('l')" onmouseleave="stop('l')" ontouchstart="event.preventDefault();go('L')" ontouchend="event.preventDefault();stop('l')" ontouchcancel="event.preventDefault();stop('l')">◀</button>
<button class="db m">DRIVE</button>
<button class="db r2" id="br" onmousedown="go('R')" onmouseup="stop('r')" onmouseleave="stop('r')" ontouchstart="event.preventDefault();go('R')" ontouchend="event.preventDefault();stop('r')" ontouchcancel="event.preventDefault();stop('r')">▶</button>
<button class="db d" id="bd" onmousedown="go('B')" onmouseup="stop('b')" onmouseleave="stop('b')" ontouchstart="event.preventDefault();go('B')" ontouchend="event.preventDefault();stop('b')" ontouchcancel="event.preventDefault();stop('b')">▼</button>
</div>
<div class="md">
<button class="mb eco a" onclick="sm('Eco')">ECO</button>
<button class="mb comf" onclick="sm('Comfort')">COMFORT</button>
<button class="mb sport" onclick="sm('Sport')">SPORT</button>
<button class="mb race" onclick="sm('Race')">RACE</button>
</div>
<div class="g2">
<button class="bt eng" id="be" onclick="te()">START</button>
<button class="bt prk on" id="bp" onclick="tp()">P BRAKE</button>
<button class="bt lgt" id="blgt" onclick="tl()">LIGHTS</button>
<button class="bt" id="bh" onmousedown="sc('hornOn')" onmouseup="sc('hornOff')" onmouseleave="sc('hornOff')" ontouchstart="event.preventDefault();sc('hornOn')" ontouchend="event.preventDefault();sc('hornOff')" ontouchcancel="event.preventDefault();sc('hornOff')">HORN</button>
</div>
<div class="ar">
<button class="ab" id="bsl" onclick="tsl()">◀</button>
<button class="ab hz" id="bhz" onclick="thz()">⚠</button>
<button class="ab" id="bsr" onclick="tsr()">▶</button>
</div>
<div class="g2">
<button class="bt pol" id="bpol" onclick="tpol()">POLICE</button>
<button class="bt" onclick="sc('cal')">CALIBRATE</button>
</div>
<div style="margin-top:8px;padding:8px;border:1px solid #222;border-radius:12px;background:#080808">
<div style="font-size:10px;color:#aaa;text-align:center;margin-bottom:6px">STEERING SERVO ADJUSTMENT</div>
<div class="g2">
<button class="bt" onclick="sc('sv-10')">-10°</button>
<button class="bt" onclick="sc('sv+10')">+10°</button>
<button class="bt" onclick="sc('sv-1')">-1°</button>
<button class="bt" onclick="sc('sv+1')">+1°</button>
</div>
<div class="g2">
<button class="bt" onclick="sc('setL')">SAVE LEFT</button>
<button class="bt" onclick="sc('setR')">SAVE RIGHT</button>
<button class="bt" onclick="sc('setC')">SAVE CENTER</button>
<button class="bt" onclick="sc('servoCenter')">GO CENTER</button>
</div>
</div>
<div class="inf"><span>TEMP <b>90°</b></span><span>FUEL <b>100%</b></span><span>MODE <b id="mv">ECO</b></span></div>
</div>
<script>
var ws,spd=0,lt=Date.now(),acc=false,rev=false,eng=false,park=true,light=false,ls=false,rs=false,hz=false,pol=false,mode='Eco';
var fwT=null,bwT=null,lT=null,rT=null;
function con(){
if(ws&&ws.readyState===WebSocket.OPEN)return;
ws=new WebSocket('ws://'+(location.hostname||'192.168.4.1')+':81/');
ws.onopen=function(){document.getElementById('s').innerText='Online';document.getElementById('s').className='ok'};
ws.onclose=function(){document.getElementById('s').innerText='Offline';document.getElementById('s').className='';setTimeout(con,2000)};
ws.onerror=function(){ws.close()}
}
function sc(c){if(ws&&ws.readyState===WebSocket.OPEN)ws.send(c)}
function go(c){
sc(c);
if(c=='F'){acc=true;rev=false;document.getElementById('bu').classList.add('on');clearInterval(fwT);fwT=setInterval(function(){sc('F')},150);}
if(c=='B'){rev=true;acc=false;document.getElementById('bd').classList.add('on');clearInterval(bwT);bwT=setInterval(function(){sc('B')},150);}
if(c=='L'){document.getElementById('bl').classList.add('on');clearInterval(lT);lT=setInterval(function(){sc('L')},150);}
if(c=='R'){document.getElementById('br').classList.add('on');clearInterval(rT);rT=setInterval(function(){sc('R')},150);}
}
function stop(c){
sc(c);
if(c=='f'){acc=false;document.getElementById('bu').classList.remove('on');clearInterval(fwT);fwT=null;}
if(c=='b'){rev=false;document.getElementById('bd').classList.remove('on');clearInterval(bwT);bwT=null;}
if(c=='l'){document.getElementById('bl').classList.remove('on');clearInterval(lT);lT=null;}
if(c=='r'){document.getElementById('br').classList.remove('on');clearInterval(rT);rT=null;}
}
function allStop(){
clearInterval(fwT);clearInterval(bwT);clearInterval(lT);clearInterval(rT);
fwT=bwT=lT=rT=null;
sc('x');
document.getElementById('bu').classList.remove('on');
document.getElementById('bd').classList.remove('on');
document.getElementById('bl').classList.remove('on');
document.getElementById('br').classList.remove('on');
acc=rev=false;
}
window.addEventListener('blur',allStop);
document.addEventListener('visibilitychange',function(){if(document.hidden)allStop();});
function te(){eng=!eng;sc(eng?'engineOn':'engineOff');if(!eng){spd=0;acc=rev=false}up()}
function tp(){park=!park;sc(park?'handBrakeOn':'handBrakeOff');if(park){spd=0;acc=rev=false}up()}
function tl(){light=!light;sc(light?'lightsOn':'lightsOff');up()}
function tpol(){pol=!pol;sc(pol?'policia':'policiaOff');up()}
function tsl(){if(hz){hz=false;sc('hazardOff')}ls=!ls;rs=false;up()}
function tsr(){if(hz){hz=false;sc('hazardOff')}rs=!rs;ls=false;up()}
function thz(){hz=!hz;sc(hz?'hazardOn':'hazardOff');if(hz){ls=rs=false}up()}
function sm(m){mode=m;sc('mode'+m);document.querySelectorAll('.mb').forEach(function(b){b.classList.toggle('a',b.textContent.toUpperCase().startsWith(m.toUpperCase()))});document.getElementById('mv').innerText=m.toUpperCase()}
function up(){
document.getElementById('be').innerText=eng?'STOP':'START';document.getElementById('be').classList.toggle('on',eng);
document.getElementById('bp').classList.toggle('on',park);
document.getElementById('blgt').classList.toggle('on',light);
document.getElementById('bpol').classList.toggle('on',pol);
document.getElementById('bsl').classList.toggle('on',ls||hz);
document.getElementById('bsr').classList.toggle('on',rs||hz);
document.getElementById('bhz').classList.toggle('on',hz);
}
function sim(){
var dt=(Date.now()-lt)/1000;lt=Date.now();if(dt>.2)dt=.2;
if(eng&&!park){
if(acc&&!rev){spd+=40*dt}else if(rev&&!acc){spd-=15*dt}else{if(spd>0){spd-=8*dt;if(spd<.5)spd=0}if(spd<0){spd+=8*dt;if(spd>-.5)spd=0}}
}else{spd=0}
if(spd>200)spd=200;if(spd<-15)spd=-15;
document.getElementById('v').innerText=Math.round(Math.abs(spd));
var g=(spd==0&&!acc&&!rev)?(park?'P':'N'):(spd>0?'D':'R');
document.getElementById('g').innerText=g;document.getElementById('g').className=g;
}
setInterval(sim,100);
document.addEventListener('keydown',function(e){
var k=e.key.toLowerCase();
if(k=='w'){go('F');e.preventDefault()}if(k=='s'){go('B');e.preventDefault()}
if(k=='a'){go('L');e.preventDefault()}if(k=='d'){go('R');e.preventDefault()}
if(k==' '){e.preventDefault();tp()}if(k=='l')tl();if(k=='h')thz();if(k=='f')sc('hornOn');if(k=='p')tpol();
if(k=='m'){var ms=['Eco','Comfort','Sport','Race'];sm(ms[(ms.indexOf(mode)+1)%4])}
});
document.addEventListener('keyup',function(e){
var k=e.key.toLowerCase();
if(k=='w')stop('f');if(k=='s')stop('b');if(k=='a')stop('l');if(k=='d')stop('r');if(k=='f')sc('hornOff');
});
con();up();
</script></body></html>
)rawliteral";

void buzzTone(int f){if(f<=0){ledcWriteTone(buzz,0);ledcWrite(buzz,0);return;}ledcWrite(buzz,128);ledcWriteTone(buzz,f);}
void buzzOff(){ledcWriteTone(buzz,0);ledcWrite(buzz,0);}

const bool STEERING_REVERSED = false;

const int SERVO_MIN_US = 500;
const int SERVO_MAX_US = 2500;

int Lmin = 35;
int Rmax = 145;
int Cmid = 90;
int ang  = 90;

unsigned long lastSteerMove = 0;
unsigned long manualSteerUntil = 0;

int angleToUs(int a){
  a = constrain(a, 0, 180);
  return map(a, 0, 180, SERVO_MIN_US, SERVO_MAX_US);
}

void servoRawWrite(int a){
  ang = constrain(a, 0, 180);
  steering.writeMicroseconds(angleToUs(ang));
  Serial.print("SERVO ANG=");
  Serial.println(ang);
}

void servoWriteSafe(int a){
  int lo = min(Lmin, Rmax);
  int hi = max(Lmin, Rmax);
  a = constrain(a, lo, hi);
  servoRawWrite(a);
}

void save(){
  pref.begin("c",false);
  pref.putInt("l",Lmin);
  pref.putInt("r",Rmax);
  pref.putInt("c",Cmid);
  pref.end();
  Serial.print("SAVED L="); Serial.print(Lmin);
  Serial.print(" C="); Serial.print(Cmid);
  Serial.print(" R="); Serial.println(Rmax);
}

void load(){
  pref.begin("c",true);
  Lmin = pref.getInt("l",35);
  Rmax = pref.getInt("r",145);
  Cmid = pref.getInt("c",90);
  pref.end();

  if(Lmin < 0 || Lmin > 180) Lmin = 35;
  if(Rmax < 0 || Rmax > 180) Rmax = 145;
  if(Cmid < 0 || Cmid > 180) Cmid = 90;
  if(abs(Rmax-Lmin) < 20){ Lmin=35; Rmax=145; Cmid=90; }

  ang = Cmid;
}

void calibrate(){
  Lmin = 35;
  Rmax = 145;
  Cmid = 90;
  ang = Cmid;
  servoRawWrite(Cmid);
  save();
}

void manualServoStep(int delta){
  manualSteerUntil = millis() + 8000;
  servoRawWrite(ang + delta);
}

void setLeftLimitHere(){
  Lmin = ang;
  save();
}

void setRightLimitHere(){
  Rmax = ang;
  save();
}

void setCenterHere(){
  Cmid = ang;
  save();
}

void goCenterNow(){
  manualSteerUntil = millis() + 3000;
  servoRawWrite(Cmid);
}

void updateSteering(){
  if(millis() < manualSteerUntil) return;

  if(millis() - lastSteerMove < 20) return;
  lastSteerMove = millis();

  int stepTurn = 2;
  int stepReturn = 2;

  if(mode=="Eco") stepTurn = 2;
  else if(mode=="Comfort") stepTurn = 3;
  else if(mode=="Sport") stepTurn = 4;
  else if(mode=="Race") stepTurn = 5;

  if(left && !right){
    if(STEERING_REVERSED) servoWriteSafe(ang + stepTurn);
    else                  servoWriteSafe(ang - stepTurn);
  }
  else if(right && !left){
    if(STEERING_REVERSED) servoWriteSafe(ang - stepTurn);
    else                  servoWriteSafe(ang + stepTurn);
  }
  else{
    if(ang < Cmid){
      ang += stepReturn;
      if(ang > Cmid) ang = Cmid;
      servoRawWrite(ang);
    }
    else if(ang > Cmid){
      ang -= stepReturn;
      if(ang < Cmid) ang = Cmid;
      servoRawWrite(ang);
    }
  }
}

void setup(){
  Serial.begin(115200);
  pinMode(leftEndstop,INPUT_PULLUP);pinMode(rightEndstop,INPUT_PULLUP);
  pinMode(headL,OUTPUT);pinMode(headR,OUTPUT);pinMode(turnL,OUTPUT);pinMode(turnR,OUTPUT);
  pinMode(polR1,OUTPUT);pinMode(polR2,OUTPUT);pinMode(polB1,OUTPUT);pinMode(polB2,OUTPUT);
  ledcAttach(buzz,2000,8);

  steering.setPeriodHertz(50);
  steering.attach(steerPin,SERVO_MIN_US,SERVO_MAX_US);
  tractionMotor.attach(motorPin);

  load();
  ang = Cmid;
  servoRawWrite(Cmid);
  delay(500);

  WiFi.mode(WIFI_AP);WiFi.softAP(AP_SSID,AP_PASS);
  server.on("/",[](){
    server.sendHeader("Cache-Control","no-store, no-cache, must-revalidate");
    server.sendHeader("Pragma","no-cache");
    server.send_P(200,"text/html",HTML);
  });
  server.onNotFound([](){server.send(404,"text/plain","404");});
  server.begin();
  webSocket.begin();
  webSocket.onEvent([](uint8_t n,WStype_t t,uint8_t*p,size_t l){
    if(t==WStype_DISCONNECTED){
      fw=bw=left=right=false;
      haz=pol=horn=false;
      goCenterNow();
      return;
    }
    if(t==WStype_TEXT){String c;c.reserve(l);for(size_t i=0;i<l;i++)c+=(char)p[i];
      c.trim();
      unsigned long now = millis();
      if(c=="L"){left=true;lastLeftCmd=now;}else if(c=="l")left=false;
      else if(c=="R"){right=true;lastRightCmd=now;}else if(c=="r")right=false;
      else if(c=="F"){fw=true;lastFwCmd=now;}else if(c=="f")fw=false;
      else if(c=="B"){bw=true;lastBwCmd=now;}else if(c=="b")bw=false;
      else if(c=="engineOn")eng=true;else if(c=="engineOff"){eng=false;fw=bw=left=right=false;}
      else if(c=="handBrakeOn")park=true;else if(c=="handBrakeOff")park=false;
      else if(c=="lightsOn")light=true;else if(c=="lightsOff")light=false;
      else if(c=="hazardOn"){haz=true;pol=false;}else if(c=="hazardOff")haz=false;
      else if(c=="policia"){pol=true;haz=false;}else if(c=="policiaOff")pol=false;
      else if(c=="hornOn")horn=true;else if(c=="hornOff")horn=false;
      else if(c=="modeEco")mode="Eco";else if(c=="modeComfort")mode="Comfort";
      else if(c=="modeSport")mode="Sport";else if(c=="modeRace")mode="Race";
      else if(c=="cal")calibrate();
      else if(c=="sv-10")manualServoStep(-10);
      else if(c=="sv+10")manualServoStep(10);
      else if(c=="sv-1")manualServoStep(-1);
      else if(c=="sv+1")manualServoStep(1);
      else if(c=="setL")setLeftLimitHere();
      else if(c=="setR")setRightLimitHere();
      else if(c=="setC")setCenterHere();
      else if(c=="servoCenter")goCenterNow();
      else if(c=="x"){fw=bw=left=right=false;horn=false;goCenterNow();}
    }
  });
  Serial.println("OK");Serial.println(WiFi.softAPIP());
}

void loop(){
  server.handleClient();webSocket.loop();
  while(Serial.available()){String c=Serial.readStringUntil('\n');c.trim();
    unsigned long now = millis();
    if(c=="L"){left=true;lastLeftCmd=now;}else if(c=="l")left=false;
    else if(c=="R"){right=true;lastRightCmd=now;}else if(c=="r")right=false;
    else if(c=="F"){fw=true;lastFwCmd=now;}else if(c=="f")fw=false;
    else if(c=="B"){bw=true;lastBwCmd=now;}else if(c=="b")bw=false;
    else if(c=="cal")calibrate();
    else if(c=="sv-10")manualServoStep(-10);
    else if(c=="sv+10")manualServoStep(10);
    else if(c=="sv-1")manualServoStep(-1);
    else if(c=="sv+1")manualServoStep(1);
    else if(c=="setL")setLeftLimitHere();
    else if(c=="setR")setRightLimitHere();
    else if(c=="setC")setCenterHere();
    else if(c=="servoCenter")goCenterNow();
  }

  refreshCmdTimeout();

  unsigned long n=millis();
  if(n-t>=25){
    t=n;

    float mp=.78,ac=.12,br=.16;
    if(mode=="Eco"){mp=.7;ac=.105;br=.15;}
    else if(mode=="Comfort"){mp=.82;ac=.125;br=.165;}
    else if(mode=="Sport"){mp=.94;ac=.145;br=.18;}
    else if(mode=="Race"){mp=1;ac=.17;br=.2;}
    tpower=(!eng||park)?0:(fw&&!bw)?mp:(bw&&!fw)?-.78:0;
    float s=(abs(tpower)>abs(power))?ac:br;
    if(power<tpower)power=min(power+s,tpower);
    else if(power>tpower)power=max(power-s,tpower);
    if(abs(power)<.015)power=0;
    int off=0;
    if(abs(power)>.02){off=14+(int)(61*abs(power));if(power<0)off=-off;}
    tractionMotor.write(constrain(90-off,0,180));

    updateSteering();

    digitalWrite(headL,light);digitalWrite(headR,light);
    if(pol){if(n-tPol>=150){tPol=n;pStep=(pStep+1)%4;}bool r=pStep<2;digitalWrite(polR1,r);digitalWrite(polR2,r);digitalWrite(polB1,!r);digitalWrite(polB2,!r);}
    else{digitalWrite(polR1,0);digitalWrite(polR2,0);digitalWrite(polB1,0);digitalWrite(polB2,0);}
    if(n-tHaz>=400){tHaz=n;hState=!hState;}
    bool rev=(bw&&eng&&!park);
    if(haz||rev){digitalWrite(turnL,hState);digitalWrite(turnR,hState);}
    else if(left){digitalWrite(turnL,hState);digitalWrite(turnR,0);}
    else if(right){digitalWrite(turnR,hState);digitalWrite(turnL,0);}
    else{digitalWrite(turnL,0);digitalWrite(turnR,0);}

    if(horn){buzzTone(520);}
    else if(pol){buzzTone(pStep<2?880:620);}
    else if(bw&&eng&&!park){if(n-tRev>=500){tRev=n;iState?buzzOff():buzzTone(900);iState=!iState;}}
    else if((left||right||haz)&&eng){if(n-tInd>=400){tInd=n;iState?buzzOff():buzzTone(800);iState=!iState;}}
    else{buzzOff();iState=false;}
  }
}
