{**************************************************************}
                  program WS2300_Master;
{**************************************************************}
{S. Taborek}
{Version 1.3 am 02.06.2005}
{Stand : 14.06.2005}
{Stand : 24.06.2005}
{**************************************************************}


{$NOSHADOW}


Device = mega8, VCC=4.9;


Import SysTick, RTclock, SerPort,  TWINet;

From System Import longword ;

Define
  ProcClock      = 16000000;        {Hertz}
  SysTick        = 10;              {msec}
  StackSize      = $0096, iData;
  FrameSize      = $0064, iData;
  SerPort        = 38400, Stop2;    {Baud, StopBits|Parity}
  RxBuffer       = 32, iData;
  TxBuffer       = 32, iData;
  //
  TWInetMode     = Master;
  TWInode        = 02;             {address in slave mode}
  TWIpresc       = TWI_BR100;      {Bitrate}
  TWIframe       = 56, iData;      {buffer/packet size}
  TWIframeBC     = 4;              {Broadcast Frame size}
  //
  RTClock        = iData, DateTime; {Time, DateTime}
  RTCsource      = SysTick;


//uses Unit_Types;

Implementation

{$IDATA}

{--------------------------------------------------------------}
{ Type Declarations }

type

  TReply         = array[0..31]of Byte;
 
  TRAMDATENRec      = Record
                      Rec_jj        : byte;     //1
                      Rec_mm        : byte;     //2
                      Rec_dd        : byte;     //3
                      Rec_hh        : byte;     //4
                      Rec_mi        : byte;     //5
                      //..........................
                      TempInn       : Integer;  //6..7        1
                      TempOut       : Integer;  //8..9        2
                      HumidityOut   : Word;     //10..11      3
                      WindSpeed     : word;     //12..13      4
                      WindDir       : Word;     //14..15      5
                      AirPressRel   : Word;     //16..17      6
                      DewPoint      : Word;     //18..19      7
                      RainTotal     : Word;     //20..21      8
                      OkBits        : Byte;     //22  für Werte 1..8
                      //...........................
                      CRS           : Byte;     //23
                    end;

  //folgener Record muss in Größe gleich dem TRAMSaveRec sein!
  TRAMContrRec    = Record
                      RecStart_jj   : byte;     //1
                      RecStart_mm   : byte;     //2
                      RecStart_dd   : byte;     //3
                      RecStart_st   : byte;     //4
                      RecStart_mi   : byte;     //5
                      RecSize       : byte;     //6
                      MAX_DevNr     : byte;     //7
                      SaveZyk       : byte;     //8
                      Akt_WrSnr     : word;     //9..10
                      Last_RdPC     : word;     //11..12 letzter DS an PC
                      Last_AnzPC    : word;     //13..14
                      IdentCode     : word;     //15..16
                      voll          : boolean;  //17
                      d             : byte;     //18
                      MasterStatus  : byte;     //19
                      WSS_SlvStatus : byte;     //20
                      RAM_SlvStatus : byte;     //21
                      LCD_Slvstatus : byte;     //22
                      CRS           : byte;     //23
                    end;

  TRAM_DS         = array[1..sizeOf(TRAMDATENRec)] of byte;
  //da RAM-Wetterdaten und Ctrl-Daten gleich groß sind,
  //wird TRAM_DS auch als TRAM_CDS verwendet

  TTime1          = array[1..3{4}] of byte;


//.................................................

  //folgender Record darf die Größe von TWIframe nicht übersteigen!!
  //Der Record enthält alle Messwerte der Wetterstation - auch jene,
  //die nicht im I2C-RAM archiviert werden.

  TWSTSlaveDS    = Record
                     cmd            : byte;              //1
                     Time           : TTime1;            //2..4   4
                     Date           : TTime1;            //5..7
                     TempInnen      : Integer;           //8..9
                     TempAussen     : Integer;           //10..11
                     HumidityInn    : word;              //12..13
                     HumidityOut    : word;              //14..15
                     WindFlag       : byte;              //16
                     WindCode       : Byte;              //17
                     WindSpeed      : word;              //18..19
                     WindDir        : array[1..7]of byte;//20..26
                     AirPressRel    : Word;              //27..28
                     Rain1H         : word;              //29..30
                     RainTotal      : word;              //31..32
                     DewPoint       : word;              //33..34
                     Reserve        : byte;              //35
                     WSSensorExt    : byte;              //36
                     MW_Status      : word;              //37..38 für alle MW
                     WSConnErr      : word;              //39..40
                     Last_RdPC      : word;              //41..42
                     MasterStatus   : byte;              //43  >> LED s
                     WSS_Slv_Status : byte;              //44
                     RAM_Slv_Status : byte;              //45
                     LCD_Slv_status : byte;              //46
                     RAMCapacity    : longword;          //47..50
                     r1             : longword;
                   end;

  //folgender Record darf die Größe von TWIframe nicht übersteigen!!
  TRAMSlaveRec   = Record
                     cmd            : byte;            //1
                     qui            : byte;            //2
                     Akt_WrSnr      : word;            //3..4
                     CtrlDS         : TRAMContrRec;    //Controldaten  5..28
                     WetterDS       : TRAMDATENRec;    //Wetterdaten  29..51
                     r1             : longword;
                  end;
                 
{--------------------------------------------------------------}
{ Const Declarations }
const
  BroadCNode    : byte = $00;
  MasterNode    : byte = $02;
  WSTSlvNode    : byte = $03;
  RAMSlvNode    : byte = $04;
  LCDSlvNode    : byte = $05;
  BatSlvNode    : byte = $06;
 
const

  FM24C_Adr       : byte = $50;   //Moduladr. im Datenblatt: 10100000b

  SlvTimeOut      : byte  = 20;   // 20x SysTick = 200msec
 
  TxFrameSize     : byte  = sizeOf(TWSTSlaveDS);
  TxLCDFrameSize  : byte  = SizeOf(TWSTSlaveDS);

  TimeoutLimit    : byte = 230;  //für Timeoutüberwachung der ser.Schnittst.

  CRAM_ZykTime    : byte = 10;   //Anzahl Minuten bis Speicherung

const
  RAMCtrlCode     : word = $abcd;
  RAM_MAX_DevNr   : byte = 3;     //0..3  für Anzahl FM24C256
  RAMDevCapacit   : word = 32768; //Bytes pro Device
  RAMRecSize      : byte = sizeOf(TRAMDATENRec);
  RAMDS_proDev    : word = RAMDevCapacit div word(RAMRecSize);
  RAM_MAX_Snr     : word = ((RAM_MAX_DevNr + 1)* RAMDS_proDev) -1; //
  RAMContrDSAdr   : word = 0;     //Datensatzadresse für Control-Daten

  //-----------------------------

  ClearBuffer     : byte = $01;   //broadcast for Slv to clear Rx state

  cmd_01          : byte = $01;
  cmd_02          : byte = $04;
  cmd_03          : byte = $15;
  cmd_04          : byte = $17;
  cmd_05          : byte = $19;
  cmd_06          : byte = $31;
  cmd_07          : byte = $43;
  cmd_08          : byte = $07;
  cmd_09          : byte = $13;

  qui_01          : byte = $A1;
  qui_02          : byte = $A4;
  qui_03          : byte = $A7;
  qui_04          : byte = $A9;

  kenng1          : byte = $37;
  kenng2          : byte = $32;
  kenng3          : byte = $31;
  kenng4          : byte = $33;
  kenng5          : byte = $35;
  kenng6          : byte = $36;
  kenng8          : byte = $38;
  kenng9          : byte = $A2;
  kenngA          : byte = $AA;
  kenngB          : byte = $BB;
  kenngC          : byte = $CC;

//es folgen Messwert-Kennzeichnungen:

  CTempInn        : word  = 1;
  CTempOut        : word  = 2;
  CHumyInn        : word  = 4;
  CHumyOut        : word  = 8;
  CWindFlag       : word  = 16;
  CWindCode       : word  = 32;
  CWindSpd        : word  = 64;
  CWindDir        : word  = 128;
  CAirPress       : word  = 256;
  CRain1H         : word  = 512;
  CRainTot        : word  = 1024;
  CDewPoint       : word  = 2048;
  CWSSensExt      : word  = 4096;
{--------------------------------------------------------------}

{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}
var
  NetTimeOut           : SysTimer8;
  twistate             : tTWINetState;
  //
  NetTxRec[@TWITXBUFF] : TWSTSlaveDS;
  NetRxRec[@TWIRXBUFF] : TWSTSlaveDS;

  WstDaten             : TWSTSlaveDS;
  //
  RAMTxRec[@TWITXBUFF] : TRAMSlaveRec;
  RAMRxRec[@TWIRXBUFF] : TRAMSlaveRec;
  //
  RAMRX_Rec            : TRAMSlaveRec;
  RAM_DatenDS          : TRAMDATENRec;
  RAM_WDS[@RAM_DatenDS]: TRAM_DS; //array
  RAM_ContrDS          : TRAMContrRec;
  RAM_CDS[@RAM_ContrDS]: TRAM_DS; //array
  RAM_DS_S             : TRAM_DS;
  DS_Saved             : boolean;
  RAM_voll             : boolean;
//  RAMCDS_OK            : boolean;
  RAM_Wr_Snr           : word;
  RAM_PC_Snr           : word;  //hält snr temporär
  RAM_ZykTime          : byte;
  RAMCapacity          : longword;
//  RAMCpA[@RAMCapacity] : array[1..4] of byte;
  Prot_B_Aktiv         : boolean;
  Ref_DL               : word;
  ANr_PC               : word;
 
   winddir1            : byte;
   dcf_time            : boolean;
   time_sync           : boolean;
   tick_min            : boolean;
   tick_std            : boolean;
   ret                 : boolean;
   bcnt                : byte;
   w,hw                : word;
   lw                  : longword;
   iw                  : integer;
   s                   : string[27];
   c1,c2,i,j,h         : byte;
   se, mi, st          : byte;
   dd, mm, jj          : byte;
   pc_snr              : word;
   pc_s_cnt            : integer;
   pc_l_cnt            : integer;
  
//   Ma_con_err          : word;
//   Sl_prs_err          : word;
//   Ma_tio_err          : word;

{--------------------------------------------------------------}
{ functions }


procedure RTCtickMinute;      // CallBack from RTCclock
begin
  tick_min := true;
end;

procedure RTCtickHour;        // CallBack from RTCclock
begin
  tick_std := true;
end;

{==============================================================}
procedure RTC_TimeLesen;
{==============================================================}
begin
  disableints;
   se := RTCGetSecond;
   mi := RTCGetMinute;
   st := RTCGetHour;
  enableints;
end;

{==============================================================}
procedure RTC_DateLesen;
{==============================================================}
begin
  disableints;
   dd := RTCGetDay;
   mm := RTCGetMonth;
   jj := RTCGetYear;
  enableints;
end;


{==============================================================}
function SendFrame(node, frsize : byte) : boolean;
{==============================================================}
var
  timeout  : boolean;
begin     //Senden der Daten im Puffer:  NetTxRec
  SetSysTimer(NetTimeOut, SlvTimeOut);
  Timeout:= false;
  //timeout occurs after 200msec -> 20 retries
  while not(TWItxFrame(node, frsize {TxFrameSize}) or Timeout) do
    TWItxClear;  //tx failed, clear own states
    mDelay(10);  //Zeit für Slave
    timeout:= isSysTimerZero(NetTimeOut);
  endwhile;
  if Timeout then
    TWItxClear;
    //slave has to clear all its states
    TWItxBroadcast(ClearBuffer, 0, 0);    // cmd, subnode, count
    mDelay(50);
    SetSysTimer(NetTimeOut, SlvTimeOut);
    Timeout:= false;
    // timeout occurs after 200msec -> 20 retries
    while not(TWItxFrame(node, frsize {TxFrameSize}) or Timeout) do
      TWItxClear;  // 
      mDelay(10);  //Zeit für Slave
      timeout:= isSysTimerZero(NetTimeOut);
    endwhile;
  endif;
  //
  if timeout then  // Die Sendung war fehlerhaft!!
  //      WriteLn(SerOut,  Tx Timeout );
  endif;
  return(not timeout);
end;


{==============================================================}
function ReceiveFrame(Node : byte) : boolean;
{==============================================================}
var
  timeout  :  boolean;
begin
  SetSysTimer(NetTimeOut, SlvTimeOut);
  Timeout:= false;
  TWIrxClear;
  while not(TWIrxFrame(node) or Timeout) do  //Empfang  NetRxRec
    TWIrxClear;  //rx failed, clear own states
    mDelay(10);  //Zeit für Slave !!!
    timeout:= isSysTimerZero(NetTimeOut);  //timeout nach 200msec -> 20mal
  endwhile;
  if Timeout then
    //    inc(Ma_tio_err);
    //    WriteLn(SerOut,  Rx Timeout 1 );
    TWIrxClear;
    //slave has to clear all its states
    TWItxBroadcast(ClearBuffer, 0, 0);     // cmd, subnode, count
    mDelay(50);
    SetSysTimer(NetTimeOut, SlvTimeOut);
    Timeout:= false;
    //timeout occurs after 200msec -> 20 retries
    while not(TWIrxFrame(node) or Timeout) do
      TWIrxClear;  //tx failed, clear own states
      mDelay(10);  //Zeit für Slave !!!
      timeout:= isSysTimerZero(NetTimeOut);
    endwhile;
  endif;
  return(not timeout);
end;


{--------------------------------------------------------------}
function RDWR_ADR(snr_:word; var devnr:byte):word;
{--------------------------------------------------------------}
begin
  //Die I2C-RAMs werden addressiert, indem zur Basisadresse (das
  //entspricht dem 1.Modul) die Adressoffsets 1 bis 7 addiert
  //werden. Somit können max 8 Module adressiert werden.
  devnr := Byte((snr_ div (RAMDS_proDev)));
  if devnr <= RAM_MAX_DevNr then
    snr_  := snr_ - (RAMDS_proDev * word(devnr));
    snr_  := snr_ * RAMRecSize;     //Berechnen der Byte-Adresse
    devnr := FM24C_Adr or devnr;    //Hardware-Adresse
  endif;
  return(snr_);
end;


{==============================================================}
function FM24ReadDS(ReadSnr_:word; var Satz:TRAM_DS): boolean;
{==============================================================}
var result  : boolean;
    devadr_ : byte;
begin
  Readsnr_ := RDWR_ADR(ReadSnr_, devadr_); //Adressumrechnung
  result  := TWIout(devadr_, ReadSnr_);
  result  := result or TWIinp(devadr_, satz);
  return(result);
end;


{==============================================================}
function FM24WriteDS(WriteSnr_:word; Satz:TRAM_DS): boolean;
{==============================================================}
var result  : boolean;
    devadr_ : byte;
begin
  WriteSnr_ := RDWR_ADR(WriteSnr_, devadr_); //Adressumrechnung
  result    := TWIout(devadr_, WriteSnr_, satz);
  return(result);
end;


{--------------------------------------------------------------}
function    DateTimeLesen:boolean;
{--------------------------------------------------------------}
var ret:boolean;
    tsum : byte;
begin
  with WstDaten do
    tsum := Time[1] or Time[2] or Time[3];
    if (Time[1] < 24)and(Time[2] < 60)and (Time[3] < 60)and
       (tsum > 0) and
       (Date[1] > 0)and(Date[1] < 32)and
       (Date[2] > 0)and(Date[2] < 13)and
       (Date[3] > 0)and(Date[3] < 99) then
      st  := WstDaten.Time[1];
      mi  := WstDaten.Time[2];
      se  := WstDaten.Time[3];
      dd  := WstDaten.Date[1];
      mm  := WstDaten.Date[2];
      jj  := WstDaten.Date[3];
      disableints;
          RTCsetSecond(se);
          RTCsetMinute(mi);
          RTCsetHour(st);
      enableints;
      ret := true;
    else
      ret := false;
    endif;
  endwith;
  return(ret);
end;


{--------------------------------------------------------------}
function SIOPufferLeeren:boolean;
{--------------------------------------------------------------}
var c_:byte;
begin
  ret := false;
  while serstat do
    mdelay(5);
    c_  := serinp;    //Puffer leeren
    ret := true;
  endwhile;
  return(ret);
end;


{--------------------------------------------------------------}
function WetterDatenHolen:boolean;
{--------------------------------------------------------------}
begin
  NetTxRec.cmd:= cmd_01;
  if SendFrame(WSTSlvNode, 2) then  //Daten anfordern
    WstDaten.cmd := 0;
    h := 4;
    repeat
      mdelay(600);
      if ReceiveFrame(WSTSlvNode) then
        WstDaten := NetRxRec;            //Datensatz übergeben
      endif;
      dec(h);
    until (WstDaten.cmd = cmd_09)or (h = 0);
    return(h > 0);
  else
    return(false);
  endif;
end;


{--------------------------------------------------------------}
function GetSumCode(RAM_DS_:TRAM_DS):byte;
{--------------------------------------------------------------}
var ps:word;
begin
  ps := 0;
  for i := 1 to (RAMRecSize -1) do
    ps := ps + word(RAM_DS_[i]);
  endfor;
  return(hi(ps) xor lo(ps));
end;


{--------------------------------------------------------------}
function ReadRAMControlSatz(neu_ds:boolean):boolean;
{--------------------------------------------------------------}
var dl:byte;
begin
//Lesen des Control-Records aus dem RAM:
    dl := 4;
    Repeat
      dec(dl);
      mdelay(20);
    until (FM24ReadDS(RAMContrDSAdr, RAM_CDS))or(dl = 0);
    if (dl = 0) then
      //MasterStatus melden:
      RAM_ContrDS.MasterStatus:= RAM_ContrDS.MasterStatus or $20 {32};
      RAM_ContrDS.CRS := GetSumCode(RAM_CDS); //
      FM24WriteDS(RAMContrDSAdr, RAM_CDS);
      return(false);
    endif;
    //---------------
    if neu_ds then //Ctrl-DS neu definieren:
      //  Writeln(SerOut, ControlCode neu );
      RAM_ContrDS.IdentCode   := RAMCtrlCode; //Ident
      RAM_ContrDS.RecStart_jj := jj;
      RAM_ContrDS.RecStart_mm := mm;
      RAM_ContrDS.RecStart_dd := dd; //
      RAM_ContrDS.RecStart_st := st;
      RAM_ContrDS.RecStart_mi := mi;
      RAM_ContrDS.Akt_WrSnr   := 1;  //RAM Datensatznummer für Neustart
      RAM_ContrDS.RecSize     := RAMRecSize;
      RAM_ContrDS.MAX_DevNr   := RAM_MAX_DevNr;
      RAM_ContrDS.Last_RdPC   := 0;     //  für PC
      RAM_ContrDS.SaveZyk     := RAM_ZykTime;     //
      RAM_ContrDS.voll        := false;
      RAM_ContrDS.MasterStatus:= $44;
      RAM_ContrDS.CRS         := GetSumCode(RAM_CDS); //
    endif;

    if (RAM_ContrDS.IdentCode = RAMCtrlCode)then {Ident-Test}
      if (GetSumCode(RAM_CDS) = RAM_CDS[RAMRecSize]) then
        //      if (TestSumCode(RAM_CDS)) then
        //            Writeln(SerOut, CRS OK );
        return(true);
      else
        //   Writeln(SerOut, CRS Err );
        //MasterStatus melden:
        RAM_ContrDS.MasterStatus:= RAM_ContrDS.MasterStatus or $01;
        RAM_ContrDS.CRS := GetSumCode(RAM_CDS); //raus aus der Schlinge
        FM24WriteDS(RAMContrDSAdr, RAM_CDS);
        return(false);
      endif;
    endif;
    //
  return(true);
end;


{--------------------------------------------------------------}
function RAMDatenRecSpeichern(snr_:word):boolean;
{--------------------------------------------------------------}
//wenn snr_ = 0 dann wird nur der Control-DS gesichert
//da jeder DS seine Zeitstempel bekommt, kann PC archivieren
var ret:boolean;
begin
  if dcf_time = false then   //wird true beim ersten Sync
    return(false);
  endif;
  //
  if Snr_<> RAMContrDSAdr then  //nicht nur Contr-Satz sichern
  //
    if FM24WriteDS(Snr_, RAM_WDS) then
      ret := true;
    else
      ret := false;
    endif;
  endif;
  //
  //----Speicherauslastung berechnen----
  //Achtung: Compilerprobleme mit der Function abs  !
  iw := (integer(RAM_ContrDS.Last_RdPC) - integer(RAM_ContrDS.Akt_WrSnr));
  if RAM_ContrDS.Akt_WrSnr < RAM_ContrDS.Last_RdPC then
    RAMCapacity := longword(RAM_MAX_Snr - abs(iw));
  else
    RAMCapacity := longword(abs(iw));
  endif;
  RAMCapacity := (100000 * RAMCapacity) div longword(RAM_MAX_Snr);
  //------------------------------------
  RAM_ContrDS.CRS := GetSumCode(RAM_CDS); //RAM_Contr overlays RAM_CDS
  FM24WriteDS(RAMContrDSAdr, RAM_CDS);  //Contr-Satz sichern
  return(ret);
end;


{==============================================================}
function  RAMSlave_DatenEmpfangen:boolean;
{==============================================================}
//RAMRxRec[@TWIRXBUFF] : TRAMSlaveRec;
begin
  mdelay(200);
  if ReceiveFrame(RAMSlvNode) then
    RAMRx_Rec := RAMRxRec;  //Daten kopiern
    case RAMRx_Rec.cmd of
      cmd_01: //RAM_Slv schickt Daten zwecks Anzeige
         RAM_DatenDS := RAMRx_Rec.WetterDS; //Datensatz übergeben
         // nicht RAMDatenRecSpeichern(RAM_Wr_Snr); //daten sichern
         |
      cmd_07: //angeforderter DS trifft ein:
         //hier trifft RAM-DS mit berechneten Mittelwerten ein
         RAM_DatenDS := RAMRx_Rec.WetterDS; //Datensatz übergeben
         if RAMDatenRecSpeichern(RAM_Wr_Snr) then //daten sichern
           //Satzpointer weiterzählen:
           RAM_Wr_Snr := RAM_ContrDS.Akt_WrSnr + 1;
           if (RAM_Wr_Snr >= RAM_MAX_Snr) then
             RAM_Wr_Snr := 1;  //Überschreiben beginnt evtl jetzt
           endif;
           RAM_ContrDS.Akt_WrSnr := word(RAM_Wr_Snr);
         else
           //Satznummer darf nicht weitergezählt werden:
           //Akt_WrSnr
         endif;
         tick_min := false;
         DS_Saved := true;
         |
    endcase;
    return(true);
  else
    // receive failed
    // inc(Ma_con_err);
    return(false);
  endif;
end;


{--------------------------------------------------------------}
function DS_Senden(snr1:word; kn:byte):boolean;
{--------------------------------------------------------------}
var i5:byte;
begin
  if FM24ReadDS(snr1, RAM_DS_S) then  //lesen der Dates
    SerOut(Kn); SerOut(Kn); //Kennung senden
    SerOut(RAMRecSize + 2); //Anzahl der nun folgenden Bytes:
    SerOut(lo(Snr1)); SerOut(hi(Snr1));
    if kn = kenng8 then
      RAM_DS_S := RAM_WDS;  //aktueller Satz aus RAM-Slave
    endif;
    for i5 := 1 to RAMRecSize do   //Daten
      SerOut(RAM_DS_S[i5]);
    endfor;
    return(true);
  else
    SerOut($FD); SerOut($FD); SerOut(0); //Error  253
    return(false);
  endif;
end;

{--------------------------------------------------------------}
function WordReadFromCOM:word;
{--------------------------------------------------------------}
var wd1        : word;
    ada1[@wd1] : array[1..2] of byte;
    h6, j6     : byte;
begin
  h6 := 0; j6 := 0;
  repeat
    if serstat then
      inc(j6);
      ada1[j6] := SerInp;    //Empfang einer Word-Adresse
    endif;
    if h6 > 1 then mdelay(7); endif;
    inc(h6);
  until (j6 = 2) or (h6 > 75);
  if (j6 = 2) then
    return(wd1);
  else
    return($FFFF); //in diesem Zusammenhang möglich
  endif;
end;


{--------------------------------------------------------------}
function DS_SendenWS(snr5:word; kn:byte):boolean;
{--------------------------------------------------------------}
begin
  if DS_Senden(snr5, kn) then //gewünschter DS
    return(true);
  else
    return(false);
  endif;
end;


{--------------------------------------------------------------}
procedure PC_DatenSenden;
{--------------------------------------------------------------}
var wd       : word;
    ada[@wd] : array[1..2] of byte;
    snr      : word;
begin
  //
  c1 := 0;
  h  := 0;
  repeat
    if SerStat then
      c1 := SerInp;
    endif;
    if h > 0 then mdelay(10); endif;
    inc(h);
  until (c1 > 0) or (h > 7);
  //  SIOPufferLeeren;  nicht hier
  //--------------
  //Es werden stets mindestens 3 Byte zurückgesendet:
  //1. Kennungswiederholung
  //2. Kennungswiederholung
  // Anzahl der folgenden Bytes
  case c1 of
   kenng2: //Speicherzyklus ändern
          ada[1] := 9; ada[2] := 111;
          wd := WordReadFromCOM;       //wd overlay ada
          //Zyklus muss kleiner als 60 sein, da min mod zyk !
          if (ada[1] = ada[2])and(ada[1] < 60)and(ada[1] > 1) then
            RAM_ZykTime := ada[1];
            SerOut(kenng2); SerOut(ada[1]); SerOut(0);
            RAM_ContrDS.SaveZyk := RAM_ZykTime;
            RAM_ContrDS.CRS     := GetSumCode(RAM_CDS); //RAM_Contr overlays
RAM_CDS
            RAMDatenRecSpeichern(RAMContrDSAdr);
          else
            SerOut($F2); SerOut($F2); SerOut(0); //Error
          endif;
         |
   kenng3: //RAM-Control-DS auslesen und senden:
           DS_Senden(RAMContrDSAdr, kenng3); //aktueller Ctrl-DS
           Prot_B_Aktiv := false;
         |
   kenng4: //Reset des DL:
          wd := WordReadFromCOM;
          if wd =   RAMCtrlCode then
            ReadRAMControlSatz(true); //DS neu erstellen
            RAMDatenRecSpeichern(RAMContrDSAdr);
            SerOut(kenng4); SerOut(kenng4); SerOut(0); //Error
          else
            SerOut($F4); SerOut($F4); SerOut(0); //Error
          endif;
         |
   kenng6: //Angefordert ein bestimmter DS
          snr := WordReadFromCOM;  //snr wird empfangen
          if (snr > 0)and(snr < RAM_MAX_Snr) then
            DS_SendenWS(snr, kenng6);
          else
            SerOut($F6); SerOut($F6); SerOut(0); //Error
          endif;
         |
   Kenng8: if not Prot_B_Aktiv then
             DS_Senden(word(RAM_Wr_Snr), kenng8);  //aktueller DS
           endif;
         |
   kenngA: //Anzahl DS anfordern seit letzter Übernahme
           //im Ctrl-Ds wird jeweils nach einer Datenübernahme die
           //RAM-Satznummer gespeichert und bei einer erneuten
           //Übernahme wird ab dieser Satznummer fortgesetzt.
          pc_snr := WordReadFromCOM;
          //
          SerOut(kenngA); SerOut(kenngA);
          SerOut(2); //Anzahl der nun folgenden Sende-Bytes = 2
          SerOut(lo(pc_snr)); //Snr zurücksenden
          SerOut(hi(pc_snr)); //Snr zurücksenden
          Prot_B_Aktiv := true; //Bereit für Protokollteil B
         |
   kenngB://Anfordern eines bestimmten DS zwecks definitiver Übernahme.
          //Die snr soll in Folge sein. Bevor dieser Teil des
          //Protokolls benutzt wird, muss mit kenngA eröffnet werden.
          //Die Quittierung der Übernahme durch den PC
          //erfolgt abschließend über kenngC.
          if Prot_B_Aktiv then
            if DS_SendenWS(pc_snr, kenngB) then
              //nach diesem Aufruf ist PC_Snr als die vom PC gewünschte snr
              //definiert:
              inc(pc_snr);
              if (pc_snr > RAM_MAX_Snr-1) then
                pc_snr := 1;
              endif;
            else
              //andernfalls wurde PC informiert, dass Anfrage fehlerhaft
              SerOut($FB); SerOut($FB); SerOut(0); //Error
              RAM_ContrDS.Last_RdPC := word(PC_Snr);
              RAMDatenRecSpeichern(RAMContrDSAdr);
            endif;
          else
          endif;
         |
   kenngC:// Das Übernahme-Protokoll wird hier abgeschlossen.
          // Der Master erstellt den neuen RAM_Ctrl-DS
          // nach der Datenübertragung an den PC:
          if Prot_B_Aktiv then
            ReadRAMControlSatz(true); //DS neu erstellen
            RAM_ContrDS.Last_RdPC := word(PC_Snr);
            RAM_ContrDS.Akt_WrSnr := word(RAM_Wr_Snr);
            RAMDatenRecSpeichern(RAMContrDSAdr);
            SerOut(kenngC); SerOut(kenngC); SerOut(0); //Error
          else
            SerOut($FC); SerOut($FC); SerOut(0); //Error
          endif;
          Prot_B_Aktiv := false;
         |
     else
       SerOut($F9); SerOut($F9); SerOut(0); //Error
  endcase;
  SIOPufferLeeren;
end;


{--------------------------------------------------------------}
procedure InitVar;
{--------------------------------------------------------------}
begin
  tick_std    := true;
  time_sync   := false; // RTC-Uhr muss gestellt werden
  WstDaten.Date[1] := 255;
  //  Ma_con_err  := 0;
  //  Sl_prs_err  := 0;
  //  Ma_tio_err  := 0;
  DS_Saved    := true;  // damit die Speicherung nicht sofort beginnt
  RAM_voll    := false;
  //  pc_readed   := false;
  //  pc_kenng    := $F1;
  Prot_B_Aktiv := false;
end;


{--------------------------------------------------------------}
{ Main Program  WS2300-Datenlogger-Master}
{$IDATA}

begin
  InitVar;
  TWIrxClear;
  EnableInts;
  //
  //------Uhrzeit von WS2300 holen---------------
  h := 0;
  dcf_time := false;  //wird erst durch WS2300-Time true
  while (h < 72)and(dcf_time = false) do
    if WetterDatenHolen then  //Daten anfordern incl. Zeit
      if (WstDaten.WSS_Slv_Status and %00000011) > 0 then
        if DateTimeLesen then
          dcf_time := true;
          h := 100;
        endif;
      endif;
    else
      mdelay(800);
      TWItxBroadcast(ClearBuffer, 0, 0);  // cmd, subnode, count
    endif;
    mdelay(2000);
    inc(h);
  endwhile;

  mdelay(4000);     // 1 mal warten bis LCD_Start abgelaufen!!!

  //------1.Controlsatz  übernehmen-------
  repeat
  until ReadRAMControlSatz(false); //hier fehlt Timeout-Kontr.
  //
  RAMDatenRecSpeichern(RAMContrDSAdr);  //berechnet RAMCapacity

  RAM_ZykTime:= RAM_ContrDS.SaveZyk; //kann vom PC parametr. werden
  pc_snr     := (RAM_ContrDS.Last_RdPC); //für Start
  RAM_Wr_Snr := RAM_ContrDS.Akt_WrSnr;          //!!!
  //
  //
  //==================Hauptschleife======================
  //
  loop
    //------------Datenverteilung-------------
    if WetterDatenHolen then //Daten von WS2300 anfordern u holen
    //              Writeln(SerOut, WDaten von WS-Slv );
      NetTxRec := NetRxRec; //TX-Buffer mit RX-Buffer füllen
      //---hier die Daten für den LCD_Slave vorbereiten
      NetTxRec.RAMCapacity := RAMCapacity; // siehe RAMDatenRecSpeichern
      NetTxRec.cmd := cmd_08;  //Kennung für aktuellere Daten
      SendFrame(LCDSlvNode, TxLCDFrameSize);  //Daten an LCDSlv weitersenden
      //---hier die Daten für den RAM-Slave vorbereiten
      NetTxRec.cmd  := cmd_02;  //auch Auforderungscode für MiW-Speichern
      if SendFrame(RAMSlvNode,TxFrameSize) then //Daten an RAMSlv senden
        mdelay(30);
        RAMSlave_DatenEmpfangen;
      endif;
    endif;
    //
    //---------Zyklische Speicherung der Wetterdaten---------
    if (mi mod RAM_ZykTime = 0)and(not DS_Saved) then
      RAMTxRec.cmd  := cmd_01;  //Anforderungscode für RAM_DS
      if SendFrame(RAMSlvNode,TxFrameSize) then   //DS anfordern
        mdelay(200);
        RAMSlave_DatenEmpfangen;
        //nur wenn Daten empfangen, wird DS_saved = true
      else
      endif{SendFrame};
    else
      //nächste RAM-Speicherung anstoßen:
      if tick_min then
        RTC_TimeLesen;
        DS_Saved := false;  //fordert die nächste Sicherung
        tick_min := false;
      endif;
    endif{min_cnt};
    //
    //RTC-UHR stellen:   nach je 1 Std
    if tick_std then
      RTC_DateLesen;
      time_sync := false;  //damit DCF-Time erneut gelesen wird
      tick_std  := false;
      //
    endif;
    if not time_sync then
      if DateTimeLesen then
        //
        time_sync := true;
        dcf_time := true;
      else
        dcf_time := false;
      endif;
    endif;
    //-----------------------------------------------
    for i := 1 to 200 do   //Pollen in der Warteschleife
      if SerStat then //PC-Anfrage
        c1 := SerInp;
        mdelay(2);
        if c1 = Kenng1 then
          PC_DatenSenden;
          mdelay(5);
        else
          SerOut($F0); SerOut($F0); SerOut(0); //Error
          SIOPufferLeeren;
          mdelay(30);
        endif;
      else
        mdelay(30);
      endif;
    endfor;

  endloop;
  //
end WS2300_Master.
Projekt Datenlogger für Wetterstation WS2300

Quelltext: Master-Modul