MainServer.pas 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. unit MainServer;
  2. {$MODE Delphi}
  3. interface
  4. uses
  5. LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics,
  6. Controls, Forms, Dialogs, ComCtrls, StdCtrls, CheckLst, ExtCtrls,
  7. Snap7;
  8. Const
  9. DBSize = 2048;
  10. type
  11. { TFrmServer }
  12. TFrmServer = class(TForm)
  13. Log: TMemo;
  14. SB: TStatusBar;
  15. Panel1: TPanel;
  16. PC: TPageControl;
  17. TabSheet1: TTabSheet;
  18. TabSheet2: TTabSheet;
  19. TabSheet3: TTabSheet;
  20. StartBtn: TButton;
  21. EdIP: TEdit;
  22. Label1: TLabel;
  23. StopBtn: TButton;
  24. List: TCheckListBox;
  25. TabSheet4: TTabSheet;
  26. Label2: TLabel;
  27. lblMask: TLabel;
  28. MemoDB1: TMemo;
  29. MemoDB2: TMemo;
  30. MemoDB3: TMemo;
  31. EvtTimer: TTimer;
  32. Splitter1: TSplitter;
  33. LogTimer: TTimer;
  34. procedure ListClick(Sender: TObject);
  35. procedure FormCreate(Sender: TObject);
  36. procedure LogTimerTimer(Sender: TObject);
  37. procedure StartBtnClick(Sender: TObject);
  38. procedure StopBtnClick(Sender: TObject);
  39. procedure EvtTimerTimer(Sender: TObject);
  40. procedure FormDestroy(Sender: TObject);
  41. private
  42. { Private declarations }
  43. Server : TS7Server;
  44. FMask : longword;
  45. TIM : packed array[0..DBSize-1] of byte;
  46. DB1 : packed array[0..DBSize-1] of byte;
  47. DB2 : packed array[0..DBSize-1] of byte;
  48. DB3 : packed array[0..DBSize-1] of byte;
  49. FServerStatus: integer;
  50. FClientsCount: integer;
  51. procedure UpdateMask;
  52. procedure MaskToForm;
  53. procedure MaskToLabel;
  54. procedure SetFMask(const Value: longword);
  55. procedure DumpData(P : PS7Buffer; Memo : TMemo; Count : integer);
  56. procedure SetFServerStatus(const Value: integer);
  57. procedure SetFClientsCount(const Value: integer);
  58. public
  59. { Public declarations }
  60. DB1_changed : boolean;
  61. DB2_changed : boolean;
  62. DB3_changed : boolean;
  63. property LogMask : longword read FMask write SetFMask;
  64. property ServerStatus : integer read FServerStatus write SetFServerStatus;
  65. property ClientsCount : integer read FClientsCount write SetFClientsCount;
  66. end;
  67. var
  68. FrmServer: TFrmServer;
  69. implementation
  70. {$R *.lfm}
  71. procedure ServerCallback(usrPtr : pointer; PEvent : PSrvEvent; Size : integer);
  72. {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF}
  73. begin
  74. // Checks if we are interested in this event.
  75. // We need to update DB Memo contents only if our DB changed.
  76. // To avoid this check, an alternative way could be to mask
  77. // the Server.EventsMask property.
  78. if (PEvent^.EvtCode=evcDataWrite) and // write event
  79. (PEvent^.EvtRetCode=0) and // succesfully
  80. (PEvent^.EvtParam1=S7AreaDB) then // it's a DB
  81. begin
  82. case PEvent^.EvtParam2 of
  83. 1 : TFrmServer(usrPtr).DB1_changed:=true;
  84. 2 : TFrmServer(usrPtr).DB2_changed:=true;
  85. 3 : TFrmServer(usrPtr).DB3_changed:=true;
  86. end;
  87. end;
  88. end;
  89. { TFrmServer }
  90. procedure TFrmServer.DumpData(P: PS7Buffer; Memo: TMemo; Count: integer);
  91. Var
  92. SHex, SChr, SOfs : string;
  93. Ch : AnsiChar;
  94. c, cnt, ofs : integer;
  95. begin
  96. Memo.Lines.Clear;
  97. Memo.Lines.BeginUpdate;
  98. SHex:='';SChr:='';cnt:=0;ofs:=0;
  99. try
  100. for c := 0 to Count - 1 do
  101. begin
  102. SHex:=SHex+IntToHex(P^[c],2)+' ';
  103. Ch:=AnsiChar(P^[c]);
  104. if not (Ch in ['a'..'z','A'..'Z','0'..'9','_','$','-',#32]) then
  105. Ch:='.';
  106. SChr:=SChr+String(Ch);
  107. inc(cnt);
  108. if cnt=16 then
  109. begin
  110. SOfs:=IntToHex(ofs,4);
  111. Memo.Lines.Add(SOfs+' - '+SHex+' '+SChr);
  112. SHex:='';SChr:='';
  113. cnt:=0;
  114. ofs:=ofs+16;
  115. end;
  116. end;
  117. // Dump remainder
  118. if cnt>0 then
  119. begin
  120. while Length(SHex)<48 do
  121. SHex:=SHex+' ';
  122. SOfs:=IntToHex(ofs,4);
  123. Memo.Lines.Add(SOfs+' - '+SHex+' '+SChr);
  124. end;
  125. finally
  126. Memo.Lines.EndUpdate;
  127. end;
  128. end;
  129. procedure TFrmServer.EvtTimerTimer(Sender: TObject);
  130. begin
  131. if DB1_changed then
  132. begin
  133. DumpData(@DB1,MemoDB1, SizeOf(DB1));
  134. DB1_changed :=false;
  135. end;
  136. if DB2_changed then
  137. begin
  138. DumpData(@DB2,MemoDB2, SizeOf(DB2));
  139. DB2_changed :=false;
  140. end;
  141. if DB3_changed then
  142. begin
  143. DumpData(@DB3,MemoDB3, SizeOf(DB3));
  144. DB3_changed :=false;
  145. end;
  146. end;
  147. procedure TFrmServer.FormCreate(Sender: TObject);
  148. var
  149. ThePlatform : string;
  150. Wide : string;
  151. begin
  152. // Cosmetics
  153. // Infamous trick to get the platform size
  154. // Maybe it could not work ever, but we need only a form caption....
  155. case SizeOf(NativeUint) of
  156. 4 : Wide := ' [32 bit]';
  157. 8 : Wide := ' [64 bit]';
  158. else Wide := ' [?? bit]';
  159. end;
  160. {$IFDEF MSWINDOWS}
  161. ThePlatform:='Windows platform';
  162. {$ELSE}
  163. Platform:='Unix platform';
  164. {$ENDIF}
  165. Caption:='Snap7 Server Demo - '+ThePlatform+Wide+
  166. {$IFDEF FPC}
  167. ' [Lazarus]';
  168. {$ELSE}
  169. ' [Delphi/RAD studio]';
  170. {$ENDIF}
  171. PC.ActivePageIndex:=0;
  172. DumpData(@DB1,MemoDB1,SizeOf(DB1));
  173. DumpData(@DB2,MemoDB2,SizeOf(DB2));
  174. DumpData(@DB3,MemoDB3,SizeOf(DB3));
  175. StopBtn.Enabled:=false;
  176. FServerStatus:=-1; // to force update on start
  177. FClientsCount:=-1;
  178. // Server creation
  179. Server:=TS7Server.Create;
  180. // Add some shared resources
  181. Server.RegisterArea(srvAreaDB, // it's DB
  182. 1, // Number 1 (DB1)
  183. @DB1, // Its address
  184. SizeOf(DB1)); // Its size
  185. Server.RegisterArea(srvAreaDB,2,@DB2,SizeOf(DB2)); // same as above
  186. Server.RegisterArea(srvAreaDB,3,@DB3,SizeOf(DB3)); // same as above
  187. Server.RegisterArea(srvAreaTM,0,@TIM,SizeOf(TIM));
  188. // Setup the callback
  189. Server.SetEventsCallback(@ServerCallback, self);
  190. // Note
  191. // Set the callback and set Events/Log mask are optional,
  192. // we call them only if we need.
  193. // Also Register area is optional, but a server without shared areas is
  194. // not very useful :-) however it works and it's recognized by simatic manager.
  195. LogMask:=Server.LogMask; // Get the current mask, always $FFFFFFFF on startup
  196. end;
  197. procedure TFrmServer.LogTimerTimer(Sender: TObject);
  198. Var
  199. Event : TSrvEvent;
  200. begin
  201. // Update Log memo
  202. if Server.PickEvent(Event) then
  203. begin
  204. if Log.Lines.Count>1024 then // In case you want to run this demo for several hours....
  205. Log.Lines.Clear;
  206. Log.Lines.Append(SrvEventText(Event));
  207. end;
  208. // Update other Infos
  209. ServerStatus:=Server.ServerStatus;
  210. ClientsCount:=Server.ClientsCount;
  211. end;
  212. procedure TFrmServer.FormDestroy(Sender: TObject);
  213. begin
  214. Server.Free;
  215. end;
  216. procedure TFrmServer.UpdateMask;
  217. Var
  218. c: Integer;
  219. BitMask : longword;
  220. begin
  221. BitMask:=$00000001;
  222. for c := 0 to 31 do
  223. begin
  224. if List.Checked[c] then
  225. FMask:=FMask or BitMask
  226. else
  227. FMask:=FMask and not BitMask;
  228. BitMask:=BitMask shl 1;
  229. end;
  230. Server.LogMask:=FMask;
  231. end;
  232. procedure TFrmServer.ListClick(Sender: TObject);
  233. begin
  234. UpdateMask;
  235. MaskToLabel;
  236. end;
  237. procedure TFrmServer.MaskToForm;
  238. Var
  239. c: Integer;
  240. BitMask : longword;
  241. begin
  242. BitMask:=$00000001;
  243. for c := 0 to 31 do
  244. begin
  245. List.Checked[c]:=(FMask and BitMask)<>0;
  246. BitMask:=BitMask shl 1;
  247. end;
  248. end;
  249. procedure TFrmServer.MaskToLabel;
  250. begin
  251. lblMask.Caption:='$'+IntToHex(FMask,8);
  252. end;
  253. procedure TFrmServer.SetFClientsCount(const Value: integer);
  254. begin
  255. if FClientsCount <> Value then
  256. begin
  257. FClientsCount := Value;
  258. SB.Panels[1].Text:='Clients : '+IntToStr(FClientsCount);
  259. end;
  260. end;
  261. procedure TFrmServer.SetFMask(const Value: longword);
  262. begin
  263. if FMask <> Value then
  264. begin
  265. FMask := Value;
  266. MaskToForm;
  267. MaskToLabel;
  268. end;
  269. end;
  270. procedure TFrmServer.SetFServerStatus(const Value: integer);
  271. begin
  272. if FServerStatus <> Value then
  273. begin
  274. FServerStatus := Value;
  275. case FServerStatus of
  276. SrvStopped : SB.Panels[0].Text:='Stopped';
  277. SrvRunning : SB.Panels[0].Text:='Running';
  278. SrvError : SB.Panels[0].Text:='Error';
  279. end;
  280. end;
  281. end;
  282. procedure TFrmServer.StartBtnClick(Sender: TObject);
  283. Var
  284. res : integer;
  285. begin
  286. res :=Server.StartTo(EdIP.Text);
  287. if res=0 then
  288. begin
  289. StartBtn.Enabled:=false;
  290. EdIP.Enabled:=false;
  291. StopBtn.Enabled:=true;
  292. end
  293. else
  294. SB.Panels[2].Text:=SrvErrorText(res);
  295. end;
  296. procedure TFrmServer.StopBtnClick(Sender: TObject);
  297. begin
  298. Server.Stop;
  299. StopBtn.Enabled:=false;
  300. StartBtn.Enabled:=true;
  301. EdIP.Enabled:=true;
  302. end;
  303. end.