其中的一部分。。。
library TD;
uses
TollDisplays, Devices;
{$R *.res}
function ClassFactory: TDeviceClass
stdcall;
begin
Result := TTollDisplay;
end;
exports
ClassFactory;
begin
end.
unit TollDisplays;
interface
uses
Devices, SerialPorts;
type
TTollDisplay = class(TDevice)
private
FPort : TSerialPort;
public
constructor Create(aOwner: IDevice
const aName: ShortString)
override;
destructor Destroy
override;
function Open: Integer
override;
function Close: Integer
override;
function Write(const Buffer
Count: Integer): Integer
override;
end;
TTollDisplayClass = class of TTollDisplay;
implementation
uses
Classes, SysUtils, IniFiles;
constructor TTollDisplay.Create(aOwner: IDevice
const aName: ShortString);
var
IniFile : TIniFile;
Port : String;
PortParam : TSerialParam;
begin
inherited Create(aOwner, aName);
IniFile := TIniFile.Create(ChangeFileExt(ParamStr(0), '.INI'));
try
with IniFile do
begin
Port := ReadString( aName, '端口', 'COM1');
PortParam.BaudRate := ReadInteger(aName, '波特率', 9600)
//9600
PortParam.Parity := ReadInteger(aName, '校验', 0)
//n
PortParam.ByteSize := ReadInteger(aName, '数据位', 8)
//8
PortParam.StopBits := ReadInteger(aName, '停止位', 2)
//2
end;
finally
IniFile.Free;
end;
FPort := TSerialPort.Create(Self, Port);
FPort.IOCtrl(0, @PortParam)
//设置通讯参数
end;
destructor TTollDisplay.Destroy;
begin
if Active then Close;
FreeAndNil(FPort);
inherited Destroy;
end;
function TTollDisplay.Open: Integer;
begin
Result := 0;
if not Active then
begin
Result := FPort.Open;
if Result = 0 then inherited Open;
end;
end;
function TTollDisplay.Close: Integer;
begin
Result := 0;
if Active then
begin
inherited Close;
Result := FPort.Close;
end;
end;
function TTollDisplay.Write(const Buffer
Count: Integer): Integer;
var
CmdList : TStrings;
Data: array[0..3] of Byte;
Tmp : SmallInt;
S : String;
begin
Result := -1;
if Active and (Count > 0) then //命令有效
begin
CmdList := TStringList.Create;
try
SetLength(S, Count);
Move(Buffer, S[1], Count);
CmdList.Text := S;
FillChar(Data, SizeOf(Data), $AA)
//清屏
if CmdList.Values['亮度'] <> '0' then
begin
Data[0] := StrToIntDef(CmdList.Values['亮度'], 2)
//亮度
Data[1] := StrToIntDef(CmdList.Values['车型'], 0) and $0F or $A0
//车型
Tmp := StrToIntDef('$'+CmdList.Values['收费额'], $AAAA)
//转换为BCD码
Data[2] := Hi(Tmp)
//费额高2位
Data[3] := Lo(Tmp)
//费额低2位
end;
//向费额显示器发送显示命令
Tmp := $F1;
FPort.Write(Tmp, 1)
//请求
FPort.Read(Tmp, 1)
//应答
FPort.Write(Data, SizeOf(Data))
//发送数据
FPort.Read(Tmp, 1)
//读校验码, 忽略校验
Tmp := $F8
//显示
FPort.Write(Tmp, 1);
Result := Count;
finally
CmdList.Free;
end;
end;
end;
end.
unit DeviceManagers;
interface
uses
Classes, Singleton, Devices;
type
//驱动程序
TDriver = class(TObject)
private
FDevice : IDevice;
FDriver : String;
FHandle : THandle;
FClassFactory : function: TDeviceClass
stdcall;
public
constructor Create(aDeviceName, aDriver: String);
destructor Destroy
override;
property Driver: String read FDriver
//驱动程序文件名
property Device: IDevice read FDevice
//设备接口
end;
type
//设备管理器
TDeviceManager = class(TSingleton)
private
FNulDevice : TDevice;
FActive : Boolean;
FItems : TList;
FOnChange : TNotifyEvent;
procedure doOnChange(Sender: TObject);
procedure setActive(aValue: Boolean);
protected
procedure Init
override;
procedure Done
override;
function getCount: Integer
virtual;
function getItems(Idx: Integer): IDevice
virtual;
public
function Open: Integer
virtual
//打开所有设备
function Close: Integer
virtual
//关闭所有设备
function Execute(var Cmd): Integer
virtual;
function DeviceByName(aName: ShortString): IDevice
virtual
//根据名称检索设备
property Active: Boolean read FActive write setActive;
property Count: Integer read getCount;
property Items[Idx: Integer]: IDevice read getItems
default;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
implementation
uses
SysUtils, IniFiles, Windows, LogFiles;
{TDriver}
constructor TDriver.Create(aDeviceName, aDriver: String);
begin
//加载驱动程序动态链接库
FHandle := LoadLibrary(PChar(aDriver));
if FHandle <> 0 then
begin
//获取接口函数
@FClassFactory := GetProcAddress(FHandle, 'ClassFactory');
if Assigned(FClassFactory) then
try
//构造设备实例
FDevice := FClassFactory.Create(nil, aDeviceName);
FDriver := aDriver;
except
TLogFile.WriteLn('设备"%s"的实例创建失败, 请检查驱动程序"%s"是否有效',
[aDeviceName, aDriver]);
end
else
begin
TLogFile.WriteLn('驱动程序"%s"接口函数不存在', [aDriver]);
end;
end
else
begin
TLogFile.WriteLn('驱动程序"%s"加载失败, 可能是文件不存在.', [aDriver]);
end;
end;
destructor TDriver.Destroy;
begin
if Assigned(FDevice) then FreeAndNil(FDevice)
//释放设备
if FHandle <> 0 then FreeLibrary(FHandle)
//释放驱动程序
inherited Destroy;
end;
{TDeviceManager}
procedure TDeviceManager.Init;
var
IniName : String;
IniFile : TIniFile;
Drv : TDriver;
DrvName : String;
DevList : TStringList;
I : Integer;
begin
inherited Init;
FNulDevice := TDevice.Create(nil, 'NUL')
//空设备
FItems := TList.Create;
//设置当前工作目录
SetCurrentDir(ExtractFileDir(ParamStr(0)));
//根据配置文件加载驱动程序
IniName := ChangeFileExt(ParamStr(0), '.INI');
IniFile := TIniFile.Create(IniName);
try
DevList := TStringList.Create;
try
with IniFile do
begin
//检索全部设备列表
ReadSection('设备', DevList);
for I := 0 to DevList.Count-1 do
begin
//逐项设备加载驱动程序
DrvName := ReadString('设备', DevList, '');
Drv := TDriver.Create(DevList, DrvName);
//设备驱动程序加载成功
if Assigned(Drv) and (Drv.Driver <> '') then
begin
Drv.Device.OnChange := doOnChange
//设备状态变化通知事件
FItems.Add(Drv);
end;
end
end;
finally
DevList.Free;
end;
finally
IniFile.Free;
end;
end;
procedure TDeviceManager.Done;
var
I : Integer;
begin
//释放驱动程序
if Assigned(FItems) then
begin
for I := FItems.Count-1 downto 0 do
begin
TDriver(FItems).Free;
end;
FItems.Free;
end;
if Assigned(FNulDevice) then FreeAndNil(FNulDevice);
inherited Done;
end;
procedure TDeviceManager.doOnChange(Sender: TObject);
begin
if Assigned(FOnChange) then FOnChange(Sender);
end;
procedure TDeviceManager.setActive(aValue: Boolean);
begin
if aValue then
begin
Open;
end
else
begin
Close;
end;
end;
function TDeviceManager.getCount: Integer;
begin
Result := FItems.Count;
end;
function TDeviceManager.getItems(Idx: Integer): IDevice;
begin
Result := nil;
if (Idx>=0) and (Idx<FItems.Count) then Result := TDriver(FItems[Idx]).Device;
end;
function TDeviceManager.DeviceByName(aName: ShortString): IDevice;
var
I : Integer;
begin
I := 0;
Result := FNulDevice;
while (Result=FNulDevice) and (I<Count) do
begin
if Items.Name = aName then Result := Items;
Inc(I);
end;
end;
function TDeviceManager.Open: Integer;
var
I : Integer;
R : Integer;
begin
Result := -1;
if not FActive then
begin
Result := FNulDevice.Open;
for I := 0 to Count-1 do
begin
if Items <> nil then
begin
R := Items.Open;
if R <> 0 then
begin
TLogFile.WriteLn('设备"%s"打开失败, 返回值=%d', [Items.Name, R]);
end;
end;
end;
if Result=0 then FActive := True;
end;
end;
function TDeviceManager.Close: Integer;
var
I : Integer;
begin
Result := -1;
if FActive then
begin
for I := 0 to Count-1 do
begin
if Items <> nil then Items.Close;
end;
Result := FNulDevice.Close;
if Result=0 then FActive := False;
end;
end;
function TDeviceManager.Execute(var Cmd): Integer;
begin
Result := -1;
if Active then
begin
Result := 0;;
end;
end;
end.