
// Ledcomm protocol implemented in logic as drop-in replacement for UART

`default_nettype none

module ledcomm (
  inout anode,
  inout cathode,

  input clk,
  input resetq,

  input  wr,
  input  rd,
  input  [7:0] tx_data,
  output [7:0] rx_data,

  output busy,
  output valid,
  output Verbindungbesteht
  //input  Dunkelheit
);

  wire Dunkelheit = 0;

  // ######   Verbindung zur Außenwelt   ######################

  wire Anode_IN;
  wire Kathode_IN;
  reg Anode_OUT;
  reg Kathode_OUT;
  reg Anode_DIR;
  reg Kathode_DIR;

  SB_IO #(.PIN_TYPE(6'b1010_01)) ioanode   (.PACKAGE_PIN(anode),   .D_OUT_0(Anode_OUT),   .D_IN_0(Anode_IN),   .OUTPUT_ENABLE(Anode_DIR)   );
  SB_IO #(.PIN_TYPE(6'b1010_01)) iokathode (.PACKAGE_PIN(cathode), .D_OUT_0(Kathode_OUT), .D_IN_0(Kathode_IN), .OUTPUT_ENABLE(Kathode_DIR) );

  // ######   Ledcomm-Protokoll   #############################


  reg [15:0] Taktteiler;

  reg  [7:0] Strahlzaehler;
  reg  [7:0] Lauschzaehler;

  reg [15:0] Lichtmuster;
  reg [15:0] Sendedaten;
  reg [15:0] Datenregister;

  reg  [7:0] Verbindungsdauer;

  reg EtwasEmpfangen;
  reg [15:0] Empfangenes;
  assign valid = EtwasEmpfangen;
  assign rx_data = Empfangenes[7:0];

  reg EtwasVersenden;
  reg [15:0] Ausgehendes;
  assign busy = EtwasVersenden;

  wire  [7:0] StrahlzaehlerN = Strahlzaehler - 1;
  wire  [7:0] LauschzaehlerN = Lauschzaehler - 1;
  wire [15:0] LichtmusterN = {Lichtmuster[14:0], ~Kathode_IN}; // Nächstes Helligkeitsbit entgegen nehmen

  assign Verbindungbesteht = Verbindungsdauer >= 18; // Verbindung besteht erst nach 18 mal Zublinkern stabil.

  always @(posedge clk)
  if (!resetq)
  begin
    Taktteiler <= 0;

    Strahlzaehler <= 0;
    Lauschzaehler <= 0;

    Lichtmuster <= 0;
    Sendedaten <= 0;
    Datenregister <= 0;

    Verbindungsdauer <= 0;

    EtwasEmpfangen <= 0;
    EtwasVersenden <= 0;

    {Kathode_DIR, Anode_DIR, Kathode_OUT, Anode_OUT } <= 4'b1100; // Beide Pins: Ausgang Low
  end
  else
  begin

    if (rd) EtwasEmpfangen <= 0;
    if (wr)
    begin
      Ausgehendes <= {8'd0, tx_data};
      EtwasVersenden <= 1;
    end

    if (Taktteiler <= 5856) Taktteiler <= Taktteiler + 1; // 24 MHz * 244 us = 5856 Takte
                       else Taktteiler <= 0;

    if ((Taktteiler == 24) & ( {Kathode_DIR, Anode_DIR, Kathode_OUT, Anode_OUT } == 4'b1110 )) // Wird gerade geladen ?
                               {Kathode_DIR, Anode_DIR, Kathode_OUT, Anode_OUT } <= 4'b0110; // Entladung kann 1 us später beginnen.

    if (Taktteiler == 0)
    begin // Tick mit 244 us

      if (Strahlzaehler != 0)
      begin
        Strahlzaehler <= StrahlzaehlerN;

        if (StrahlzaehlerN == 0)
        begin
          {Kathode_DIR, Anode_DIR, Kathode_OUT, Anode_OUT } <= 4'b1110; // Umgekehrt laden
          Lauschzaehler <= 32;
        end
        else {Kathode_DIR, Anode_DIR, Kathode_OUT, Anode_OUT } <= 4'b1101; // Leuchten lassen !

      end
      else
      begin
        Lichtmuster <= LichtmusterN; // Nächstes Helligkeitsbit entgegen nehmen

        if (LichtmusterN[4:0] == 5'b11100) // Ankommender Puls erkannt
        begin
          {Kathode_DIR, Anode_DIR, Kathode_OUT, Anode_OUT } <= 4'b1101; // Leuchten lassen !
          if (~Verbindungbesteht) Verbindungsdauer <= Verbindungsdauer + 1;

          // Nächsten ausgehenden Puls vorbereiten

          if (~Verbindungbesteht) Strahlzaehler <= 8; // Solange noch keine Verbindung besteht, Null-Pulse versenden.
          else // Verbindung besteht. Daten senden.
          begin

            if (Sendedaten != 0)
            begin // An bestehender Übertragung weiterarbeiten
              if (Sendedaten == 16'b1000_0000_0000_0000) Strahlzaehler <= 12;
                                                    else Strahlzaehler <= Sendedaten[15] ? 4 : 8 ;
              Sendedaten <= {Sendedaten[14:0], 1'b0};
            end
            else // Neue Daten holen
            begin
              if (!EtwasVersenden) Strahlzaehler <= 8;
              else
              begin
                EtwasVersenden <= 0;

                if (Ausgehendes == 0) Strahlzaehler <= 12;
                else
                begin
                  Strahlzaehler <= 4;
                  casez (Ausgehendes)
                    16'b1???????????????: Sendedaten <= {Ausgehendes[14:0],  1'b1};
                    16'b01??????????????: Sendedaten <= {Ausgehendes[13:0],  2'b10};
                    16'b001?????????????: Sendedaten <= {Ausgehendes[12:0],  3'b100};
                    16'b0001????????????: Sendedaten <= {Ausgehendes[11:0],  4'b1000};
                    16'b00001???????????: Sendedaten <= {Ausgehendes[10:0],  5'b10000};
                    16'b000001??????????: Sendedaten <= {Ausgehendes[ 9:0],  6'b100000};
                    16'b0000001?????????: Sendedaten <= {Ausgehendes[ 8:0],  7'b1000000};
                    16'b00000001????????: Sendedaten <= {Ausgehendes[ 7:0],  8'b10000000};
                    16'b000000001???????: Sendedaten <= {Ausgehendes[ 6:0],  9'b100000000};
                    16'b0000000001??????: Sendedaten <= {Ausgehendes[ 5:0], 10'b1000000000};
                    16'b00000000001?????: Sendedaten <= {Ausgehendes[ 4:0], 11'b10000000000};
                    16'b000000000001????: Sendedaten <= {Ausgehendes[ 3:0], 12'b100000000000};
                    16'b0000000000001???: Sendedaten <= {Ausgehendes[ 2:0], 13'b1000000000000};
                    16'b00000000000001??: Sendedaten <= {Ausgehendes[ 1:0], 14'b10000000000000};
                    16'b000000000000001?: Sendedaten <= {Ausgehendes[   0], 15'b100000000000000};
                    16'b0000000000000001: Sendedaten <= {                   16'b1000000000000000};
                  endcase
                end
              end // Etwas Versenden
            end // Neue Daten holen


          end // Verbindung besteht

          // Angekommende Daten bearbeiten

          if (LichtmusterN[12:0] == 13'b1111111111100) // Übertragungspuls wird mit 11 bis 14 Basiszeiten erkannt
          begin
            EtwasEmpfangen <= 1;
            Empfangenes <= Datenregister;
            Datenregister <= 0;
          end
          else
          begin
            if (LichtmusterN[8:0] == 9'b111111100) Datenregister <= {Datenregister[14:0], 1'b0}; // Null-Puls wird mit 7-10 Basiszeiten erkannt
                                              else Datenregister <= {Datenregister[14:0], 1'b1}; // Eins-Puls wird mit 3-6 Basiszeiten erkannt
          end

        end // Noch keinen ankommenden Puls erkannt
        else
        begin

          Lauschzaehler <= LauschzaehlerN;
          if (LauschzaehlerN != 0)
          begin
            Lauschzaehler <= Lauschzaehler - 1;
            {Kathode_DIR, Anode_DIR, Kathode_OUT, Anode_OUT } <= 4'b1110; // Umgekehrt laden
          end
          else
          begin // Taktlauscher-Init, wenn kein Puls erkannt wurde
            Sendedaten <= 0; // Keine Daten zum Herausrotieren und Abstrahlen ! Wichtig !
            Verbindungsdauer <= 0;

            //  Verbindungsdauer @ Synchrondauer = if Verbindungsende then

            if (Dunkelheit)
            begin // Für einen dunkelen Taktlauscher
              Strahlzaehler <= 0;
              Lauschzaehler <= 1;
              {Kathode_DIR, Anode_DIR, Kathode_OUT, Anode_OUT } <= 4'b1110; // Umgekehrt laden
            end
            else
            begin // Für einen hellen Taktlauscher
              Strahlzaehler <= 8;
              {Kathode_DIR, Anode_DIR, Kathode_OUT, Anode_OUT } <= 4'b1101; // Leuchten lassen !
            end

          end // Taktlauscher-Init

        end // LichtmusterN...

      end // Strahlzaehler <> 0

    end // Tick

  end // always

endmodule
