void preciseDelay(int us)
{
  uint32_t start = micros();
  while ((micros() - start) < (uint32_t)us) {
  }
}

void afskSetTone(bool mark)
{
  if (!afskActive) {
    return;
  }

  if (afskToneInitialized && afskMarkState == mark) {
    return;
  }

  afskMarkState = mark;
  afskToneInitialized = true;

  uint32_t f = ledcWriteTone(afskPin, mark ? markFreqHz : spaceFreqHz);
  if (f == 0) {
    Serial.println("AFSK tone setup failed");
    return;
  }
}

void afskStart()
{
  afskActive = true;
  afskToneInitialized = false;
  afskSetTone(true);   // idle = MARK
}

void afskStop()
{
  afskActive = false;
  afskToneInitialized = false;
  ledcWrite(afskPin, 0);
}

void sendBit(bool bitValue)
{
  digitalWrite(baudotPin, bitValue ? HIGH : LOW);
  afskSetTone(bitValue);
  preciseDelay(bitTimeUs);
}

void sendCode(uint8_t code)
{
  sendBit(LOW);

  for (int i = 0; i < 5; i++) {
    sendBit((code >> i) & 1);
  }

  digitalWrite(baudotPin, HIGH);
  afskSetTone(true);
  preciseDelay(bitTimeUs + bitTimeUs / 2);
}

void sendCodeAfskOnly(uint8_t code)
{
  if (!afskActive) {
    afskStart();
  }

  afskSetTone(false);
  preciseDelay(bitTimeUs);

  for (int i = 0; i < 5; i++) {
    afskSetTone((code >> i) & 1);
    preciseDelay(bitTimeUs);
  }

  afskSetTone(true);
  preciseDelay(bitTimeUs + bitTimeUs / 2);
}

void sendMotorStartPulse()
{
  digitalWrite(baudotPin, LOW);
  afskSetTone(false);
  delay(100);
  digitalWrite(baudotPin, HIGH);
  afskSetTone(true);
}