   delay(15);
 }
 
-void led_heartbeat_ack() {
+void signal_heartbeat_ack() {
   led_color(255,0,255);
   delay(10);
   led_color(255,0,255);

int cmode = 0;

int incomingByte = 0;
unsigned long heartbeat, track_last_heartbeat, track_missing_heartbeat, track_uart;
int show_missing_beat = 1;

void setup() {
  pinMode(PUSHLOCK_NO, INPUT_PULLUP);
  pinMode(PUSHLOCK_NC, INPUT_PULLUP);
  pinMode(BUTTON, INPUT_PULLUP);

  pinMode(LED_R, OUTPUT);
  pinMode(LED_G, OUTPUT);
  pinMode(LED_B, OUTPUT);
  pinMode(RUN, OUTPUT);

  attachInterrupt(digitalPinToInterrupt(BUTTON), isr_button_push, FALLING);
  attachInterrupt(digitalPinToInterrupt(PUSHLOCK_NO), isr_pushlock_change, CHANGE);
  //attachInterrupt(digitalPinToInterrupt(PUSHLOCK_NC), pushlock_open, CHANGE);

  pushlock = digitalRead(PUSHLOCK_NO);

  track_last_heartbeat = millis();
  track_missing_heartbeat = track_last_heartbeat;


}

//uart routines

void serial_flush() {
  int buf;
  while (Serial.available() > 0) {
      buf = Serial.read();
  }
}

void debug_print(char *msg) {
  Serial1.println("ok");
}

//uart messages

void send_ok() {
  Serial.println("ok");
  return;
}

void send_shutdown() {
  Serial.println("shutdown");
  return;
}

void send_abort_shutdown() {
  Serial.println("abort shutdown");
  return;
}

//states

void *server_bootable () {
  animate_bootable();

  if (((millis()-track_uart) >= WAIT_TO_SEND)) {
    //send_();
    debug_print("BOOTABLE");
    track_uart = millis();
  }

  if (digitalRead(SYSTEM_ON) == IS_ON) {
    return server_booting;
  } else {
    if (digitalRead(PUSHLOCK) == LOCKED) {
      if (last_heartbeat >= HEARTBEAT_TIMEOUT) {
        signal_server_locked();
        return server_locked;
      }
    } else {
      if (digitalRead(BUTTON) == PUSHED) {
        delay(100);
        return system_reset;
      }
    }
    return server_bootable;
  }
}

void *server_booting () {
  animate_booting();

  if (((millis()-track_uart) >= WAIT_TO_SEND)) {
    //send_();
    debug_print("BOOTING");
    track_uart = millis();
  }

  if (digitalRead(SYSTEM_ON) == IS_ON) {

    if (receivedHeartbeat > 0) {
      return server_running;
    } else {
      return server_booting;
    }

} else {

    if (digitalRead(PUSHLOCK) == LOCKED) {
      return server_locked;
    } else {
      return server_bootable;
    }

  }
}

void *server_running () {
  animate_running();

  if (((millis()-track_uart) >= WAIT_TO_SEND)) {
    //send_();
    debug_print("RUNNING");
    track_uart = millis();
  }

  if (digitalRead(SYSTEM_ON) == IS_ON) {
      if (receivedHeartbeat > 0) {
        return server_running;
      }

      if (digitalRead(PUSHLOCK) == LOCKED) {
        send_shutdown();
        return server_shutdown;
      }
  } else {
    if (digitalRead(BUTTON) == PUSHED) {
      delay(100);
      //return system_reset;
    }

    if (digitalRead(PUSHLOCK) == LOCKED) {
      return server_locked;
    } else {
      return server_bootable;
    }
  }
}

void *server_shutdown() {
  animate_shutdown();

  if (((millis()-track_uart) >= WAIT_TO_SEND)) {
    //send_();
    debug_print("SHUTDOWN");
    send_shutdown();
    track_uart = millis();
  }

  if (digitalRead(SYSTEM_ON) == IS_ON) {

    if (digitalRead(BUTTON) == PUSHED) {
      delay(100);
      send_abort_shutdown();
    }

    if (receivedHeartbeat == HEARTBEAT_SHUTDOWN_ACK) {
      return server_shutdown_active;
    } else if (receivedHeartbeat == HEARTBEAT_ABORT_ACK) {
      return server_running;
    } else {
      return server_shutdown;
    }

  } else {
    if (digitalRead(PUSHLOCK) == LOCKED) {
      return server_locked;
    } else {
      return server_bootable;
    }
  }
}

void *server_shutdown_active() {
  animate_shutdown_active();

  if (((millis()-track_uart) >= WAIT_TO_SEND)) {
    //send_();
    debug_print("SHUTDOWN ACTIVE");
    track_uart = millis();
  }

  if (digitalRead(SYSTEM_ON) == IS_ON) {

    if ((digitalRead(BUTTON) == PUSHED) || (digitalRead(PUSHLOCK) == UNLOCKED)) {
      delay(100);
      send_abort_shutdown();
    }

    if (receivedHeartbeat == HEARTBEAT_ABORT_ACK) {
      send_ok();
      return server_running;
    } else {
      return server_shutdown_active;
    }

  } else {
    if (digitalRead(PUSHLOCK) == LOCKED) {
      return server_locked;
    } else {
      return server_bootable;
    }
  }
}

void *server_hungup() {
  animate_hungup();

  if (((millis()-track_uart) >= WAIT_TO_SEND)) {
    //send_();
    debug_print("HUNG UP");
    track_uart = millis();
  }

  if (digitalRead(SYSTEM_ON) == IS_ON) {

    if ()(digitalRead(BUTTON) == PUSHED) || (get_last_heartbeat() >= TIME_UNTIL_REBOOT)) {
      delay(100);
      return system_reset;
    }

    if (receivedHeartbeat > 0) {}
      return server_running;
    } else {
      return server_hungup;
    }

  } else {
    if (digitalRead(PUSHLOCK) == LOCKED) {
      return server_locked;
    } else {
      return server_bootable;
    }
  }
}

void *server_locked() {
  animate_locked();

  if (((millis()-track_uart) >= WAIT_TO_SEND*10)) {
    //send_();
    debug_print("LOCKED");
    track_uart = millis();
  }

  if (digitalRead(SYSTEM_ON) == IS_ON) {
    if (digitalRead(PUSHLOCK) == LOCKED) {
      return server_shutdown;
    } else {
      return server_running;
    }
  } else {
    if (digitalRead(PUSHLOCK) == LOCKED) {
      return server_locked;
    } else {
      return server_bootable;
    }
  }
}

void *system_reset() {
  animate_reset();

  if (((millis()-track_uart) >= WAIT_TO_SEND)) {
    //send_();
    debug_print("SYSTEM RESET");
    track_uart = millis();
  }
  touch_run_pin();
  return server_booting;
}

void *system_shutdown() {
  animate_shutdown_active();

  if (((millis()-track_uart) >= WAIT_TO_SEND)) {
    //send_();
    debug_print("SYSTEM SHUTDOWN");
    track_uart = millis();
  }

  if (digitalRead(SYSTEM_ON) == IS_ON) {

    if ((digitalRead(BUTTON) == PUSHED) || (digitalRead(PUSHLOCK) == UNLOCKED)) {
      delay(100);
      send_abort_shutdown();
    }

    if (receivedHeartbeat > 0) {
      send_ok();
      return server_running;
    } else {
      return server_shutdown_active;
    }

  } else {
    if (digitalRead(PUSHLOCK) == LOCKED) {
      return server_locked;
    } else {
      return server_bootable;
    }
  }
}
