Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Logik Problem.


jeng - Sa 27.06.15 15:05
Titel: Logik Problem.
Hallo Community,

Habe folgendes Problem.

Ich habe ein 8 Port Relais das meine Lampen steuern Soll.
Nun, also 8 mal on oder off.

Ich brauche also eine Funktion die mir sagt ob ein Licht schon an ist.
Hab mir ein arry [0..7] of integer erstellt.
Wie kann ich das array nun prüfen ob darin nun zb. port[4] 1 oder 0 ist.

Das problem ist, wenn port1 on ist also 1 im array steht, und ich port2 auch auf 1 schalte, dann port2 ausschalte muss ich prüfen was von dem array auf 1 steht und nur den gewählten port auf 0 schalten.


Delete - Sa 27.06.15 15:34

- Nachträglich durch die Entwickler-Ecke gelöscht -


GuaAck - Sa 27.06.15 19:19

Hallo,

oft kann nur auf 8, 16 oder 32 binäre Port parallel zugeriffen werden, das hängt von der Hardware ab. Bei 8 Ports ist die Abbildung auf die 8 Bits eines Bytes sinnvoll.

Dann hat man üblicherweise ein Abbild der Zustände der Ports (als ein Byte) im Rechner oder liest sich dieses Abbild kurz vor einer Ausgabe ein. Ein OR mit $02 (=Binär 00000010) setzt Port 1 (wenn Port 0 das LSB ist) und ein AND mit $FD (=Binär 11111101) löscht Port 1. Abschließend muss das Abbild-Byte natürlich wieder an den Port ausgegeben werden (write o. ä.).

Mann sollte vermeiden, das zwei parallele Programmteile auf die gleiche Portgruppe zugreifen, dann gibt es natürlich Murks.

Viele Grüße
GuaAck


Delete - Sa 27.06.15 22:50

Hier kannst Du 32 BIT-Zustände prüfen:
http://www.swissdelphicenter.ch/torry/showcode.php?id=1341


Xion - So 28.06.15 00:17

Du kannst übrigens in Delphi auch inlined Assembler benutzen, was für hardwarenahe Anwendungen besonders schick ist.

http://www.delphipraxis.net/78592-inline-asm-fuer-win32-einsteiger-crashkurs.html

Das könnte z.B. so aussehen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure SwitchLightOff( lightID: integer {0..31});
asm
  {lightID in EAX}
  MOV EDX, $FFFFFFFE
  ROL EDX, EAX
  AND PortMask, EDX
  OUT PortMask, PortID  
end;


Etwas Vorsicht ist bei Verwendung der Register notwendig, da logischerweise der Parameter und der Self-Pointer bei einem Objekt zum Zeitpunkt des Aufrufs mit Assembler in einem Register stehen müssen und außerdem nur die Register EAX,ECX und EDX durch die Funktion verändert werden dürfen.


mandras - So 28.06.15 00:58

Ist es nicht voreilig so viele Tips zu geben, bevor
die eigentliche Frage/Problematik nicht näher ausgeführt wurde?


jeng - So 28.06.15 11:19

Hallo,

Also ich Danke euch für die vielen Gedanken Anstösse.

Ich bin nun ein bischen erschlagen von den Lösungsansätzen da ich Anfäger bin..
Nun,
da ich noch nicht weiss wie ich die register auslesen kann (hab keine api), ich aber weiss wie ich diese ports an und ausschalten kann ,habe ich versucht es auf diese weise zu Lösen.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
procedure TForm4.Switch2Switch(Sender: TObject);
begin
    //o_register[1] := 0;
       case o_register[2of

             0Begin
                   if o_register[1] = 0 then
                     begin
                        DomoSend($3c$00$ff$00$00$00$00$00$00$FE);
                        o_register[2] := 1;
                        Memo1.Lines.Add('P2 On');
                     end;
                   if o_register[1] = 1 then
                     begin
                       DomoSend($3c$ff$ff$00$00$00$00$00$00$FE);
                       o_register[2] := 1;
                       Memo1.Lines.Add('P2 On');
                    end;
                 End;

             1begin
                   if o_register[1] = 1 then
                     begin
                        DomoSend($3c$ff$00$00$00$00$00$00$00$FE);
                        o_register[2] := 0;
                       Memo1.Lines.Add('P2 Off');
                     end;
                     if o_register[1] = 0 then
                     begin
                        DomoSend($3c$00$00$00$00$00$00$00$00$FE);
                        o_register[2] := 0;
                       Memo1.Lines.Add('P2 Off');
                     end;
             end;
    end;
end;


Das ist allerdings nicht sehr effectiv und es wird ja enorm an Aufwand für 8 ports...
Ich hoffe dass ich mich jetzt besser erklären konnte.

Moderiert von user profile iconChristian S.: Code- durch Delphi-Tags ersetzt


Narses - So 28.06.15 12:27

Moin!

Die Herausforderung bei dir besteht echt darin, deine Postings zu verstehen, nicht Tipps zu geben... :lupe: :gruebel: :les: :nixweiss:

Kann es sein, dass du die Unterschiede vom Ist- zum Soll-Zustand ermitteln möchtest? Und dann nur die notwendigen Änderungen an die Hardware übertragen willst? Ehrlich gesagt bringt mich der Quelltext auch nicht weiter. Außer, dass ich mir sicher bin, dass man das optimieren kann, verstehe ich nicht, was da passiert. :?

Sind denn die Portzustände in einem Byte zusammengefasst, also überträgst du immer alle Relaiszustände auf einmal? Oder kannst/musst du die Relais einzeln ansteuern?

Wie ist das Konzept deiner GUI und der Controls aufgebaut? Im einfachsten Fall stelle ich mir 8 Checkboxen vor und beim Anklicken ändert sich der Relaiszustand.

cu
Narses


jeng - So 28.06.15 12:52

Hallo Narses,

Du hast sicherlich Recht, dass es mir schwer fällt mich richtig zu erklären, naja ich veruch mein bestes.

Wie du schon beschieben hast, hab ich auf der gui einen connect button, ein memo feld , 2 switches, und ein paar labels.

Ich muss jedesmal die ganze byte folge an das modul senden.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
procedure TForm4.DomoSend(para1: byte; port1: byte; port2: byte; port3: byte;
  port4: byte; port5: byte; port6: byte; port7: byte; port8: byte);

var
  Buf: TIdBytes;
begin

  SetLength(Buf, 14);
  // Exo1 Port1 OFF Hex: 23 3c 15 0a 01 00 00 00 00 00 00 00 00 fe
  // Exo1 Port1 ON  Hex: 23 3c 15 0a 01 ff 00 00 00 00 00 00 00 fe
  ----------------------------------Port1--2--3--4--5--6--7--8-----
  
  FillBytes(Buf, 140); 
  Buf[0] := $23;
  Buf[1] := para1; // Exo1 modul1 ist $3C, modul2 ist $60, modul 3 ist $61, etc... 
  Buf[2] := $15;
  Buf[3] := $0A;
  Buf[4] := $01;
  Buf[5] := port1;
  Buf[6] := port2;
  Buf[7] := port3;
  Buf[8] := port4;
  Buf[9] := port5;
  Buf[10] := port6;
  Buf[11] := port7;
  Buf[12] := port8;
  Buf[13] := $fe;

  IdUDPClient1.Sendbuffer(IP, strtoint(Edit2.Text), Buf);
        //  ReceivedString := IdUDPClient1.ReceiveString();
  
end;


Narses - So 28.06.15 13:02

Moin!

Ich verstehe leider immer noch nicht dein Problem. :? :nixweiss: Was hindert dich daran einfach bei einer Änderung eines Switches immer alle aktuellen Switch-Zustände zu übertragen?

cu
Narses


jeng - So 28.06.15 13:10

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Moin!


Kann es sein, dass du die Unterschiede vom Ist- zum Soll-Zustand ermitteln möchtest? Und dann nur die notwendigen Änderungen an die Hardware übertragen willst?
cu
Narses


Ich weiss ja nicht ob man das Ist / Soll Zustand nennt.

Port 1 Ist an.
23 3c 15 0a 01 ff 00 00 00 00 00 00 00 fe
Port 2 Ist an.
23 3c 15 0a 01 00 ff 00 00 00 00 00 00 fe

wie kann ich nun feststellen ob, wenn ich port 2 ausschalte nich auch port 1 ausgeschaltet wird.

Port 2 Aus.
23 3c 15 0a 01 00 00 00 00 00 00 00 00 fe
Da di 8 bytes nun auf null sind wird das ganze modul ausgeschaltet
weil ich ja den status der anderen ports nicht habe.
Also ich muss irgendwie die zustände der anderen ports speichern und abfragen!


Narses - So 28.06.15 13:17

Moin!

Wenn du den aktuellen Zustand nicht von der Hardware abfragen kannst, dann hast du ja nur deine GUI-Controls (bzw. allgemein: die im Programm gespeicherten Zustände). :nixweiss: Also überträgst du diese bei einem Klick einfach (es kann sich ja pro Ereignis nur ein Wert ändern). :idea:

cu
Narses

//Edit: oder soll der Zustand nicht nach jeder Änderung übertragen werden, so dass du Probleme hast, die Änderungen zu verfolgen?
Hm... Oder siehst du das Problem bei einem Neustart der Anwendung, da du dann den aktuellen Zustand der Hardware nicht (mehr) hast?

//Edit2: hättest du gerne mal ein Beispiel, wie ich das machen würde? Vielleicht kommen wir so weiter... :gruebel:


jeng - So 28.06.15 13:53

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Moin!

//Edit: oder soll der Zustand nicht nach jeder Änderung übertragen werden, so dass du Probleme hast, die Änderungen zu verfolgen?
Hm... Oder siehst du das Problem bei einem Neustart der Anwendung, da du dann den aktuellen Zustand der Hardware nicht (mehr) hast?

//Edit2: hättest du gerne mal ein Beispiel, wie ich das machen würde? Vielleicht kommen wir so weiter... :gruebel:


Zu verfolgen, ich glaube das ist genau die richtige Wort wahl.

wenn ich also port 1 auf 0n stelle sieht das ja so aus.

Port 1 on 23 3c 15 0a 01 ff 00 00 00 00 00 00 00 fe
nun stelle ich Port 2 zusäzlich auf on ohne port 1 auszuschalten!

Port 2 on 23 3c 15 0a 01 ff ff 00 00 00 00 00 00 fe

nun möchte ich Port2 ausschalten aber Port 1 soll an bleiben.

Port2 aus mit Port1 an: 23 3c 15 0a 01 ff 00 00 00 00 00 00 00 fe

Und da ist mein problem, wie schon erwähnt kann ich ja den status nicht abfragen, was noch auf an geschaltet ist.
Deshalb muss ich irgendwie in dem programm den zustand der anderen ports speichern.


Legende:
Nur Port 1 on 23 3c 15 0a 01 ff 00 00 00 00 00 00 00 fe
Nur Port 2 on 23 3c 15 0a 01 00 ff 00 00 00 00 00 00 fe
Nur Port 3 on 23 3c 15 0a 01 00 00 ff 00 00 00 00 00 fe
Nur Port 4 on 23 3c 15 0a 01 00 00 00 ff 00 00 00 00 fe
Nur Port 5 on 23 3c 15 0a 01 00 00 00 00 ff 00 00 00 fe
Nur Port 6 on 23 3c 15 0a 01 00 00 00 00 00 ff 00 00 fe
Nur Port 7 on 23 3c 15 0a 01 00 00 00 00 00 00 ff 00 fe
Nur Port 8 on 23 3c 15 0a 01 00 00 00 00 00 00 00 ff fe

Alles an: 23 3c 15 0a 01 ff ff ff ff ff ff ff ff fe
Alles aus: 23 3c 15 0a 01 00 00 00 00 00 00 00 00 fe

Und der zustand "muss" nach jeder änderung übertragen werden, weil ja sonst nichts geschaltet wird.
Ich glaube dass ein kleines beispiel vieleicht helfen könnte.

Ich bin dir auf jeden fall schon mal sehr dankbar für deine geduld und hilfe!!


Delete - So 28.06.15 15:04

Natürlich mußt du den Zustand speichern, was sonst?

Du hast also die ersten fünf Bytes, die immer gleich bleiben, und das letzte Byte, das auch immer auf fe bleibt. Die dazwischenliegenden Bytes stellen deine Ports dar, von 1 bis 8. Soweit okay.

Jetzt schickst du beim Programmstart eine Bytefolge, die den Port 1 einschaltet. Diese Bytefolge speicherst du. Und an dieser Bytefolge siehst du auch jederzeit, welche Ports ein- und welche ausgeschaltet sind. Willst du den Zustand eines Ports ändern, änderst du die Bytefolge entsprechend und speicherst diese wieder. So stellt diese Bytefolge immer den aktuellen Zustand dar. Wo ist da das Problem?


Narses - So 28.06.15 16:20

Moin!

OK, hier ein Beispiel:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
type
  TForm1 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure ckPortClick(Sender: TObject);
    procedure SendStateToHW;
  private
    { Private-Deklarationen }
  public
    PortState: array[0..7of Boolean;
  end;

implementation

procedure TForm1.FormCreate(Sender: TObject);
  var
    i: Integer;
    CheckBox: TCheckBox;
begin
  for i := 0 to 7 do begin
    CheckBox := TCheckBox.Create(Self);
    CheckBox.Parent := Self;
    CheckBox.Left := 16;
    CheckBox.Top := 16 +24*i;
    CheckBox.Width := 97;
    CheckBox.Height := 17;
    CheckBox.Caption := 'Port' +IntToStr(i +1);
    CheckBox.Tag := i;
    CheckBox.OnClick := ckPortClick;
    PortState[i] := FALSE;
  end;
end;

procedure TForm1.ckPortClick(Sender: TObject);
  var
    ThisCheckBox: TCheckBox;
begin
  ThisCheckBox := Sender as TCheckBox;
  PortState[ThisCheckBox.Tag] := ThisCheckBox.Checked;
  SendStateToHW;
end;

procedure TForm1.SendStateToHW;
  var
    i: Integer;
    Line: String;
begin
  Line := 'NewState=';
  for i := 0 to 7 do
    if PortState[i] then
      Line := Line +'FF,'
    else
      Line := Line +'00,';
  Memo1.Lines.Add(Line);
end;

GUI:
Screen

Bei Fragen: fragen. ;)

cu
Narses

//EDIT: Hab den Code nochmal auf dynamische Checkboxen umgestellt, damit wird es einfacher die Demo nur aus dem Code zu verstehen, ohne das Projekt öffnen zu müssen. :idea:


jeng - So 28.06.15 20:07

Wow, also das klappt ja wunderbar!!
Ich hab den code ein bischen umgebaut, aber wie gesagt genial.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
procedure TForm4.SendStateToHW;
  var
    i: Integer;
    Line: String;
    Port: array [0..7of Byte;

begin
   if not IdUDPClient1.Connected then
      Begin
         ShowMessage('Please connect.');
         Exit;
      End
   else

  //Line := 'NewState=';
  for i := 0 to 7 do
    if PortState[i] then
        // Line := Line +'FF,';
         Port[i] := $FF
      else
        //Line := Line +'00,';
        Port[i] :=  $00;
        DomoSend($3C, Port[0], Port[1], Port[2], Port[3], Port[4], Port[5], Port[6], Port[7], $FE);
        //Memo1.Lines.Add(line);
       end;

procedure TForm4.PortSwitch(Sender: TObject);
  var
    ThisSwitch: TSwitch;
 begin
  ThisSwitch := Sender as TSwitch;

  PortState[ThisSwitch.Tag] := ThisSwitch.IsChecked;
  //Memo1.Lines.Add(IntToStr(ThisSwitch.Tag));
  SendStateToHW;
end;


Ich werde noch ein bischen mit dem Democode herumspielen.
Ich Danke dir vielmals für deine Mühe.
Das hat mir jetzt sehr weiter geholfen.


Delete - So 28.06.15 22:53

Geht es um Domotic functions ?

http://help.windev.com/?100&name=site_map_soft_documentation
http://help.windev.com/?1000003108


jeng - Do 27.08.15 12:29

Hallo,

Ich hab da eine kleine Frage ;-)

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Moin!

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TForm1.SendStateToHW;
  var
    i: Integer;
    Line: String;
begin
  Line := 'NewState=';
  for i := 0 to 7 do
    if PortState[i] then
      Line := Line +'FF,'
    else
      Line := Line +'00,';
  Memo1.Lines.Add(Line);
end;

GUI:
[Bild: Screen]

Bei Fragen: fragen. ;)


Ich versuche gerade diese Procedure umzubauen. Nur komme ich nicht so richtig weiter.
Wie kann Ich mit PortState[i] meine Switches auf IsChecked setzen ohne den onclick auszuführen?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TfrmMain.SetPortOn;
Var i: integer;
    ThisSwitch: TSwitch;
Begin
   for i := 0 to 7 do
      if PortState[i] then
      ThisSwitch.IsChecked := PortState[i];  
End;


Also so funktionniert das nicht.


Delete - Do 27.08.15 20:12

- Nachträglich durch die Entwickler-Ecke gelöscht -


jeng - Di 15.09.15 21:23

Hallo,

Ich kriegs einfach nicht gebacken...

Ich habe Narses beispiel ein "bischen" ausgebaut. ;-)

Aus dem PortState array habe ich ein 2d array gebaut weil ich 16 Exo´s (aparate) mit jeweils 8 ports haben kann.

Jetzt scanne ich erst einmal den bus ab um zu schauen wievile Exos da sind, und was auch schon von ports auf dem jeweiligen Exo auf on also "FF" geschaltet ist und setze diese ports dann schon mal auf on.

Nun habe ich das problem wenn ich mich auf Exo 0 verbinde dann klappt das auch ohne probleme.
Wenn ich aber auf Exo 1 wechsele dann schaltet er mir die ports sporadisch auf on.
zb. ich klicke auf switch 1, dann geht auch port 1 an, und auf einmal dann auch port 4 oder 7...

Ich kann es leider im moment nur mit 2 exos testen da ich nur zwei hab. (weitere sind aber schon geordert).

Ich währe sehr froh für hilfe oder an verbesserungen von meinem bestimmt "grausigen code".


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
353:
354:
355:
356:
357:
358:
359:
360:
361:
362:
363:
364:
Function ExoScan(exoport: Integer): Integer; //über button click (For c := 60 to 75  do  begin  ExoScan(c);  end;)
var
  ExoSBuf: AnsiString;
  Data, X, Y, ExoAnswer: String;
  n,i,v: Integer;

Begin
  frmMain.ClearStatus;
  frmMain.ClearExo;

  frmMain.Timer1.Enabled := False;
  Data := '';
  n := 0;
  i := 0;
  v := 0;
  X := HexToString(IntToHex(exoport, 1)); // '$'+IntToHex(i, 1);
  ExoSBuf := #$04#$01#$02#$23 + X + #$00#$02#$49#$49;
  ExoAnswer := #$04#$01#$23#$00 + X + #$07// #$3b;
  sock.SendString(ExoSBuf);
  sleep(99);
  Data := sock.RecvPacket(500);
  X := Copy(Data, 36);

  if ExoAnswer = X then
     Begin
      Y := Copy(X, 51);
    //  frmMain.Memo1.Lines.Add('Exo:' + IntToStr(exoport mod 6 +1) + ' ' +
    //  StringToHex(Y)); // +' ' +Buf);
      i := exoport mod 6 +1;
      TRadioButton(frmMain.GroupBox2.Controls[i]).Enabled := True;
      TRadioButton(frmMain.GroupBox2.Controls[i]).Visible := True;
      frmMain.RadioButton1.IsChecked := True;  //immer Exo1 Auswählen nach bus scan
      for n := 60 to exoport mod 6 do
          frmMain.ExoTrue[n] := True;
        // frmMain.PortState[n,Nil] := True;
        //  frmMain.PortState1[n] := True;
      End;
      frmMain.Timer1.Enabled := True;
  //   Result :=n;
end;


Procedure TfrmMain.ScanStatus; //Hier wird gescannt im timer1 alle 1 sekunden. Soll Portstate[x,i] überschreiben! 
Const
  scan = #$05#$01;

Var
  S, X: String;
  I,Y,Exo,PortOn,n,m: Integer;
  Buf: String;
  source1: String;
begin
   {$ZEROBASEDSTRINGS OFF}
   Exo := 0;
   PortOn := 0;

  sock.SendString(scan);
  Buf := sock.RecvPacket(500);
  S := Buf.Substring(2,High(Buf));
  // Source1 := #$FF;
  source1 := #$01;

  for I := 0 to high(S) -1 do // so sind es immer 128 bytes, also maximal 16 exos a 8 ports.
     //if (I = 128) And (S[I] > source1) then 

         if S[i] > source1 then

            begin

            Exo := (I) div 8;
              if Exo = 0 then
                 PortOn := (I) mod 8 -1
              else
                 PortOn := (I) mod 8;

             //  if ExoTrue[Exo] then
                 PortState[Exo,PortOn] := True
               //  else
               //  PortState[Exo,PortOn] := False;
                //PortState1[PortOn] := True
             end;
            // Memo1.Lines.Add(Format('ScanStatus-Exo%d: %d',[Exo, PortOn])); //[(i) div 8, (i) mod 8]));
             Label13.Text := IntToStr(length(S));

End;

procedure TfrmMain.swPortClick(Sender: TObject);
var
  ThisSwitch: TSwitch;
begin

  ThisSwitch := Sender as TSwitch;
  ThisSwitch.OnClick := Nil;

  Exo := Exodet[SelectedExo];
  ExoTrue[SelectedExo] := True;
  PortState[SelectedExo,ThisSwitch.Tag] := ThisSwitch.IsChecked;
  //PortState1[ThisSwitch.Tag] := ThisSwitch.IsChecked;
  LastExoPort := ThisSwitch.Tag;

  Memo1.Lines.Add('Send to Exo:' + IntToStr(SelectedExo) + ' : ' + IntToStr(ThisSwitch.Tag));
  SendStateToHW;
  //sleep(99);
end;

procedure TfrmMain.SendStateToHW;
var
  I,N: Integer;
  Dim,IsDim: ansichar;
  Temp,Line: String;

  begin

  if IsSocketAlive(sock) = True then
  Begin
    ShowMessage('Please connect.');
    exit;
  End;
  if IsSocketAlive(sock) = False then

  Begin
    Line := 'Exo:'+IntToStr(SelectedExo)+'NewState=';
    if ExoTrue[selectedExo] then
       for i  := 0 to 7 do
        if PortState[selectedExo,i] then
        //if PortState1[i] then
           begin
      //     Line := Line +'FF,';
           Port[i] := #$FF;
           Dim := #$FE;
           end
          else
           Begin
       //    Line := Line +'00,';
           Port[i] := #$00;
           Dim := #$01;
              End;
        Memo1.Lines.Add(Line);
        DomoSend(Port[0], Port[1], Port[2], Port[3], Port[4], Port[5], Port[6], Port[7], Dim);

  End;



Procedure TfrmMain.DomoSend(port1: ansichar; port2: ansichar; port3: ansichar;
  port4: ansichar; port5: ansichar; port6: ansichar; port7: ansichar;
  port8: ansichar; para3: ansichar);
var
  Buf,Buf1: AnsiString;
  Data: String;
  I: Integer;

begin

  Data := #$04#$01#$02#$23 + Exo + #$00#$0a#$01 + port1 + port2 + port3 + port4
    + port5 + port6 + port7 + port8 + para3;

  sock.SendString(Data);// + CRLF);

  for I := 1 to High(Data) do
  begin
    Buf := Data.Substring(4,High(Data));
    Buf1 := Buf1 + StringToHex(Buf[I]);
  end;
  Memo1.Lines.Add(Buf1);
end;

Procedure SetPortOn; //hier werden die gescannten ports auf on geswitchd.

Var
  X: Integer;
  OldState: TNotifyEvent;

begin

for X := 0 to 7 do
   if frmMain.PortState[frmMain.SelectedExo,X] then
  // if frmMain.PortState1[X] then
    begin
       OldState := frmMain.u[X].OnSwitch;
       frmMain.u[X].OnSwitch := nil;
       frmMain.u[X].IsChecked := True;
       frmMain.u[X].OnSwitch := OldState;
    End
    else if frmMain.PortState[frmMain.SelectedExo,X] = False then
    //if frmMain.PortState1[X] = False then
    begin
        OldState := frmMain.u[X].OnSwitch;
        frmMain.u[X].OnSwitch := nil;
        frmMain.u[X].IsChecked := False;
        frmMain.u[X].OnSwitch := OldState;
    End;

end;

procedure TfrmMain.ClearStatus;

var n,m: integer;
Begin
  for n  := 0 to 15 do
      Begin
        for m := 0 to 7 do
           PortState[n,m] := False;
    //  PortState1[m] := False;
     // sleep(99);
      End;
End;

procedure TfrmMain.ClearExo;
Var m: integer;
begin
    for m := 0 to 15 do
     // PortState[n,m] := False;
      ExoTrue[m] := False;
     // sleep(99);
end;

procedure TfrmMain.RadioButtonClick(Sender: TObject); //Hier werden die Exos gewechselt.
Var
  I, X, Y: Integer;

Begin
   SelectedExo := 0;
{
   case (Sender as TRadioButton).Tag of
     0: Begin
        //ClearExo;
        ClearStatus;
        Memo1.lines.add('Cleared 1 ');
        End;
     1: Begin
        //ClearExo;
        ClearStatus;
        Memo1.lines.add('Cleared 2 ');
        End;
   end;
  }

  I := TRadioButton(Sender).Tag;
  Exo := Exodet[I];
  ExoTrue[I] := True;
  SelectedExo := I;
  Memo1.lines.add('Radio Change '+StringToHex(Exo)+'  ' +Exodet[I]);

End;

procedure TfrmMain.Timer1Timer(Sender: TObject); //hier wird alle 1 sec neu eingelesen und portstate neu gesetzt.
begin
   ScanStatus;
     SetPortOn;
end;

procedure TfrmMain.Timer2Timer(Sender: TObject);
begin
  Label4.Text := TimeToStr(Time - StartTime);

end;

procedure TfrmMain.FormCreate(Sender: TObject); //hier noch formcreate.
Var
  I,X: Integer;
  R: TBinaryReader;

begin
  //Memo1.VScrollBar.Value := Memo1.VScrollBar.Max;
  Label1.StyledSettings := Label1.StyledSettings - [TStyledSetting.FontColor];
  Label3.StyledSettings := Label3.StyledSettings - [TStyledSetting.FontColor];
  Label1.Text := ('Disconnected');
  Label1.FontColor := TAlphaColors.Red;
  Button1.Enabled := False;
  SelectedExo := 0;

  // RadioButton1.IsChecked := True;
  // RadioButtonTag := 1; //IsChecked := True;
  GroupBox1.Opacity :=0;
  GroupBox2.Opacity :=0;
  Memo1.Opacity :=0.5;
  Panel1.Opacity :=0;

  GroupBox1.Controls.Add(Switch1);
  GroupBox1.Controls.Add(Switch2);
  GroupBox1.Controls.Add(Switch3);
  GroupBox1.Controls.Add(Switch4);
  GroupBox1.Controls.Add(Switch5);
  GroupBox1.Controls.Add(Switch6);
  GroupBox1.Controls.Add(Switch7);
  GroupBox1.Controls.Add(Switch8);



  u[0] := Switch1;
  u[1] := Switch2;
  u[2] := Switch3;
  u[3] := Switch4;
  u[4] := Switch5;
  u[5] := Switch6;
  u[6] := Switch7;
  u[7] := Switch8;

  GroupBox2.Controls.Add(RadioButton1);
  GroupBox2.Controls.Add(RadioButton2);
  GroupBox2.Controls.Add(RadioButton3);
  GroupBox2.Controls.Add(RadioButton4);
  GroupBox2.Controls.Add(RadioButton5);
  GroupBox2.Controls.Add(RadioButton6);
  GroupBox2.Controls.Add(RadioButton7);
  GroupBox2.Controls.Add(RadioButton8);

 RadioButton1.Tag :=0;
  RadioButton2.Tag :=1;
   RadioButton3.Tag :=2;
    RadioButton4.Tag :=3;
     RadioButton5.Tag :=4;
      RadioButton6.Tag :=5;
       RadioButton7.Tag :=6;
        RadioButton8.Tag :=7;

 Switch1.Tag := 0;
  Switch2.Tag := 1;
   Switch3.Tag := 2;
    Switch4.Tag := 3;
     Switch5.Tag := 4;
      Switch6.Tag := 5;
       Switch7.Tag := 6;
        Switch8.Tag := 7;

  Exodet[0] := #$3c;
  Exodet[1] := #$3d;
  Exodet[2] := #$3e;
  Exodet[3] := #$3f;
  Exodet[4] := #$40;
  Exodet[5] := #$41;
  Exodet[6] := #$42;
  Exodet[7] := #$43;
  Exodet[8] := #$44;
  Exodet[9] := #$45;
  Exodet[10] := #$46;
  Exodet[11] := #$47;
  Exodet[12] := #$48;
  Exodet[13] := #$49;
  Exodet[14] := #$4a;
  Exodet[15] := #$4b;

  Exo := Exodet[0];
  FillChar(Port, 8#$00);     //set domoports to zero.

 
  if SaveState.Stream.Size > 0 then
  begin
    // Recover previously typed text in Edit1 control.
    R := TBinaryReader.Create(SaveState.Stream);
    try
      Edit1.Text := R.ReadString;
      Edit2.Text := R.ReadString;
      Edit3.Text := R.ReadString;
      Edit4.Text := R.ReadString;
    finally
      R.Free;
    end;

  end;

  sock := TTCPBlockSocket.Create;

end;