Created
October 16, 2013 19:54
-
-
Save wenhuizhang/7013724 to your computer and use it in GitHub Desktop.
2 Photon System Control and Medical Image Analysis_Delphi_Updated till Aug. 2013 (a new version of MPScan)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit analogu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
Menus, ToolWin, ComCtrls, ImgList, ExtCtrls, mpfileu, mpviewu; | |
type | |
TAnalogFrm = class(TForm) | |
StatusBar1: TStatusBar; | |
MainMenu1: TMainMenu; | |
Edit1: TMenuItem; | |
CopytoBitmap1: TMenuItem; | |
Panel1: TPanel; | |
ToolBar1: TToolBar; | |
ToolButton1: TToolButton; | |
ToolButton2: TToolButton; | |
ToolButton3: TToolButton; | |
ToolButton4: TToolButton; | |
ToolButton5: TToolButton; | |
ToolButton6: TToolButton; | |
ImageList1: TImageList; | |
N1: TMenuItem; | |
Axes1: TMenuItem; | |
Frame1: TMenuItem; | |
GotoFrame1: TMenuItem; | |
LastFrame1: TMenuItem; | |
FirstFrame1: TMenuItem; | |
N3: TMenuItem; | |
FastReverse1: TMenuItem; | |
Stop1: TMenuItem; | |
FastForward1: TMenuItem; | |
N4: TMenuItem; | |
PrevFrame1: TMenuItem; | |
NextFrame1: TMenuItem; | |
CopyDatatoClipboard1: TMenuItem; | |
N2: TMenuItem; | |
NewAnalogChannelsWindow1: TMenuItem; | |
procedure FormClose(Sender: TObject; var Action: TCloseAction); | |
procedure FormCreate(Sender: TObject); | |
procedure FormDestroy(Sender: TObject); | |
procedure FormPaint(Sender: TObject); | |
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, | |
Y: Integer); | |
procedure FormResize(Sender: TObject); | |
procedure ToolButton1Click(Sender: TObject); | |
procedure ToolButton2Click(Sender: TObject); | |
procedure ToolButton3Click(Sender: TObject); | |
procedure ToolButton4Click(Sender: TObject); | |
procedure ToolButton5Click(Sender: TObject); | |
procedure FirstFrame1Click(Sender: TObject); | |
procedure LastFrame1Click(Sender: TObject); | |
procedure GotoFrame1Click(Sender: TObject); | |
procedure CopytoBitmap1Click(Sender: TObject); | |
procedure FormActivate(Sender: TObject); | |
procedure FormShow(Sender: TObject); | |
procedure CopyDatatoClipboard1Click(Sender: TObject); | |
procedure Axes1Click(Sender: TObject); | |
procedure NewAnalogChannelsWindow1Click(Sender: TObject); | |
private | |
{ Private declarations } | |
bInitialized: boolean; {prevents events from firing when form is created} | |
fCurrentFrameIndex: integer; | |
trace2, trace3: TTrace; | |
f_MAX_Y_VALUE: integer; | |
ch2Rect, ch3Rect: TRect; | |
offscreenBitmap: TBitmap; | |
function AnalogXToTime(chIndex, sampleIndex: integer): string; {in ms or us} | |
function AnalogYToValue(chIndex, sampleValue: integer): string; {in units} | |
procedure DrawBackground; | |
procedure DrawTraces; | |
procedure ResizeElements; | |
procedure SetCurrentFrameIndex(newIndex: integer); | |
function YToBitmap2(y: integer): integer; | |
function YToBitmap3(y: integer): integer; | |
public | |
{ Public declarations } | |
mpFile: TMPFile; | |
yTop2, yTop3, yExtent2, yExtent3: integer; | |
procedure DrawAnalogData; | |
procedure OnNewFrame; | |
procedure Initialize(thempFile: TMPFile); | |
property CurrentFrameIndex: integer read fCurrentFrameIndex write SetCurrentFrameIndex; | |
end; | |
var | |
AnalogFrm: TAnalogFrm; | |
implementation | |
{$R *.DFM} | |
uses mainfrm, anyaxisu, cpyanaldlgu, clipbrd; | |
procedure TAnalogFrm.Initialize(thempFile: TMPFile); | |
var bCaptionOK: boolean; | |
i, j: integer; | |
s: string; | |
begin | |
mpFile := thempFile; | |
bCaptionOK := False; i := 0; | |
f_MAX_Y_VALUE := mpFile.MaxPixelValue; | |
yTop2 := f_MAX_Y_VALUE; yTop3 := yTop2; | |
yExtent2 := 2 * (f_MAX_Y_VALUE + 1); yExtent3 := yExtent2; | |
mpFile.ActiveFrameIndex := fCurrentFrameIndex; | |
{Sets caption of the form} | |
while not bCaptionOK do | |
begin | |
i := i + 1; | |
s := ExtractFileName(mpFile.filename) + '; Analog Channels - ' + IntToStr(i); | |
if mpFile.analogWndList.Count <> 0 then | |
begin | |
bCaptionOK := True; | |
for j := 0 to mpFile.analogWndList.Count - 1 do | |
if TAnalogFrm(mpFile.analogWndList.Items[j]).Caption = s then | |
bCaptionOK := False; | |
end | |
else | |
bCaptionOK := True; | |
end; | |
Caption := s; | |
bInitialized := True; | |
end; | |
procedure TAnalogFrm.SetCurrentFrameIndex(newIndex: integer); | |
begin | |
if (newIndex < 0) or (newIndex >= mpFile.FrameCount) then Exit; | |
fCurrentFrameIndex := newIndex; | |
mpFile.ActiveFrameIndex := fCurrentFrameIndex; | |
OnNewFrame; | |
end; | |
function TAnalogFrm.AnalogXToTime(chIndex, sampleIndex: integer): string; {in ms or us} | |
var dTime: double; | |
begin | |
with mpFile do | |
try | |
dtime := (sampleIndex / ChDataPtsPerFrame[chIndex] + CurrentFrameIndex) / FrameRate; | |
if dtime = 0 then | |
Result := '0 ms' | |
else if Abs(dtime) > 1E-3 then | |
Result := Format('%8.3f', [dtime * 1000]) + ' ms' | |
else | |
Result := Format('%8.3f', [dtime * 1000000]) + ' ' + Chr(181) + 's'; | |
except | |
Result := ''; | |
end; | |
end; | |
function TAnalogFrm.AnalogYToValue(chIndex, sampleValue: integer): string; {in units} | |
var dValue: double; | |
begin | |
with mpFile do | |
try | |
dValue := ChConvFactor[chIndex] * FullScaleToVal(ChInputRange[chIndex]) * | |
sampleValue / (f_MAX_Y_VALUE + 1) + ChOffset[chIndex]; | |
Result := Format('%8.3g', [dValue]) + ' ' + PrefixToString(ChPrefix[chIndex]) + | |
ChUnit[chIndex]; | |
except | |
Result := ''; | |
end; | |
end; | |
procedure TAnalogFrm.DrawBackground; | |
begin | |
with offscreenBitmap.Canvas, mpFile do | |
begin | |
Brush.Color := clBlack; | |
FillRect(Rect(0, 0, ClientWidth - 1, ClientHeight - StatusBar1.Height - 1)); | |
if AnalogChEnabled[2] and AnalogChEnabled[3] then | |
begin | |
Pen.Color := clRed; | |
MoveTo(ClientWidth div 2, 0); | |
LineTo(ClientWidth div 2, offscreenBitmap.Height - 1); | |
end; | |
end; | |
end; | |
procedure TAnalogFrm.DrawTraces; | |
var i, j, k, l, traceSize: integer; | |
begin | |
offscreenBitmap.Canvas.Pen.Color := clWhite; | |
with mpFile do | |
begin | |
if AnalogChEnabled[2] then | |
begin | |
traceSize := Length(trace2); | |
for i := 0 to traceSize - 1 do | |
begin | |
j := MulDiv(i, ChDataPtsPerFrame[2] - 1, traceSize - 1); | |
with mpFile.Frames[CurrentFrameIndex].channels[2] do | |
begin | |
trace2[i].MaxPt.y := data[j]; | |
trace2[i].MinPt.y := data[j]; | |
end; | |
k := MulDiv(i + 1, ChDataPtsPerFrame[2] - 1, traceSize - 1) - 1; | |
if k >= ChDataPtsPerFrame[2] then k := ChDataPtsPerFrame[2] - 1; | |
if j < k then | |
with mpFile.Frames[CurrentFrameIndex].channels[2] do | |
for l := j + 1 to k do | |
begin | |
if data[l] > trace2[i].MaxPt.y then trace2[i].MaxPt.y := data[l]; | |
if data[l] < trace2[i].MinPt.y then trace2[i].MinPt.y := data[l]; | |
end; | |
trace2[i].MaxPt.y := YToBitmap2(trace2[i].MaxPt.y); | |
trace2[i].MinPt.y := YToBitmap2(trace2[i].MinPt.y); | |
end; | |
Windows.PolyLine(offscreenBitmap.Canvas.Handle, trace2[0].MaxPt, 2 * (traceSize - 1)); | |
end; | |
if AnalogChEnabled[3] then | |
begin | |
traceSize := Length(trace3); | |
for i := 0 to traceSize - 1 do | |
begin | |
j := MulDiv(i, ChDataPtsPerFrame[3] - 1, traceSize - 1); | |
with mpFile.Frames[CurrentFrameIndex].channels[3] do | |
begin | |
trace3[i].MaxPt.y := data[j]; | |
trace3[i].MinPt.y := data[j]; | |
end; | |
k := MulDiv(i + 1, ChDataPtsPerFrame[3] - 1, traceSize - 1) - 1; | |
if k >= ChDataPtsPerFrame[3] then k := ChDataPtsPerFrame[3] - 1; | |
if j < k then | |
with mpFile.Frames[CurrentFrameIndex].channels[3] do | |
for l := j + 1 to k do | |
begin | |
if data[l] > trace3[i].MaxPt.y then trace3[i].MaxPt.y := data[l]; | |
if data[l] < trace3[i].MinPt.y then trace3[i].MinPt.y := data[l]; | |
end; | |
trace3[i].MaxPt.y := YToBitmap3(trace3[i].MaxPt.y); | |
trace3[i].MinPt.y := YToBitmap3(trace3[i].MinPt.y); | |
end; | |
Windows.PolyLine(offscreenBitmap.Canvas.Handle, trace3[0].MaxPt, 2 * (traceSize - 1)); | |
end; | |
end; | |
end; | |
procedure TAnalogFrm.ResizeElements; | |
var i: integer; | |
begin | |
offscreenBitmap.Width := ClientWidth; | |
offscreenBitmap.Height := ClientHeight - StatusBar1.Height - ToolBar1.Height; | |
with mpFile do | |
begin | |
if AnalogChEnabled[2] and not AnalogChEnabled[3] then | |
begin | |
ch2Rect := Rect(0, Panel1.Height, ClientWidth - 1, | |
ClientHeight - StatusBar1.Height {- Panel1.Height} - 1); | |
SetLength(trace2, ClientWidth); | |
for i := 0 to ClientWidth - 1 do | |
begin | |
trace2[i].MaxPt.x := i; | |
trace2[i].MinPt.x := i; | |
end; | |
end; | |
if not AnalogChEnabled[2] and AnalogChEnabled[3] then | |
begin | |
ch3Rect := Rect(0, Panel1.Height, ClientWidth - 1, | |
ClientHeight - StatusBar1.Height {- Panel1.Height} - 1); | |
SetLength(trace3, ClientWidth); | |
for i := 0 to ClientWidth - 1 do | |
begin | |
trace3[i].MaxPt.x := i; | |
trace3[i].MinPt.x := i; | |
end; | |
end; | |
if AnalogChEnabled[2] and AnalogChEnabled[3] then | |
begin | |
ch2Rect := Rect(0, Panel1.Height, ClientWidth div 2 - 1, | |
ClientHeight - StatusBar1.Height {- Panel1.Height} - 1); | |
ch3Rect := Rect(ClientWidth div 2 + 1, Panel1.Height, ClientWidth - 1, | |
ClientHeight - StatusBar1.Height {- Panel1.Height} - 1); | |
SetLength(trace2, ClientWidth div 2); | |
for i := 0 to (ClientWidth - 1) div 2 - 1 do | |
begin | |
trace2[i].MaxPt.x := i; | |
trace2[i].MinPt.x := i; | |
end; | |
SetLength(trace3, ClientWidth - ClientWidth div 2 - 1); | |
for i := ClientWidth div 2 + 1 to ClientWidth - 1 do | |
begin | |
trace3[i - (ClientWidth div 2 + 1)].MaxPt.x := i; | |
trace3[i - (ClientWidth div 2 + 1)].MinPt.x := i; | |
end; | |
end; | |
end; | |
end; | |
function TAnalogFrm.YToBitmap2(y: integer): integer; | |
begin | |
Result := Muldiv(y - yTop2, offscreenBitmap.Height - 1, - yExtent2 + 1); | |
if Result < 0 then Result := 0; | |
if Result > offscreenBitmap.Height - 1 then Result := offscreenBitmap.Height - 1; | |
end; | |
procedure TAnalogFrm.OnNewFrame; | |
begin | |
DrawAnalogData; | |
StatusBar1.Panels[0].Text := 'Frame: ' + IntToStr(CurrentFrameIndex + 1) + | |
'/' + IntToStr(mpFile.FrameCount); | |
end; | |
function TAnalogFrm.YToBitmap3(y: integer): integer; | |
begin | |
Result := Muldiv(y - yTop3, offscreenBitmap.Height - 1, - yExtent3 + 1); | |
if Result < 0 then Result := 0; | |
if Result > offscreenBitmap.Height - 1 then Result := offscreenBitmap.Height - 1; | |
end; | |
{********************************* PUBLIC *************************************} | |
procedure TAnalogFrm.DrawAnalogData; | |
var rc: TRect; | |
begin | |
DrawBackground; | |
DrawTraces; | |
rc := Rect(0, 0, offscreenBitmap.Width - 1, offscreenBitmap.Height - 1); | |
Canvas.CopyRect(rc, offscreenBitmap.Canvas, | |
Rect(rc.Left, rc.Top - ToolBar1.Height, rc.Right, rc.Bottom - ToolBar1.Height)); | |
end; | |
{****************************** FORM EVENTS ***********************************} | |
procedure TAnalogFrm.FormCreate(Sender: TObject); | |
begin | |
offscreenBitmap := TBitmap.Create; | |
offscreenBitmap.HandleType := bmDDB; | |
PrevFrame1.ShortCut := ShortCut(VK_LEFT, []); | |
NextFrame1.ShortCut := ShortCut(VK_RIGHT, []); | |
end; | |
procedure TAnalogFrm.FormShow(Sender: TObject); | |
begin | |
if bInitialized then ResizeElements; | |
end; | |
procedure TAnalogFrm.FormActivate(Sender: TObject); | |
begin | |
with Mainform do | |
begin | |
NewFile1.Enabled := True; | |
OpenFile1.Enabled := True; | |
if mpFile <> nil then | |
FileAs1.Enabled := mpFile.IsMemoryFile | |
else | |
FileAs1.Enabled := False; | |
FileInformation1.Enabled := True; | |
Close1.Enabled := True; | |
end; | |
end; | |
procedure TAnalogFrm.FormClose(Sender: TObject; var Action: TCloseAction); | |
begin | |
action := caFree; | |
if not Mainform.bAppClosing then mpFile.OnWndClose(self); | |
mpFile := nil; | |
end; | |
procedure TAnalogFrm.FormDestroy(Sender: TObject); | |
begin | |
offscreenBitmap.Free; | |
end; | |
procedure TAnalogFrm.FormPaint(Sender: TObject); | |
var rc: TRect; | |
begin | |
rc := Canvas.ClipRect; | |
with mpFile do | |
if AnalogChEnabled[2] or AnalogChEnabled[3] then | |
begin | |
DrawBackground; | |
DrawTraces; | |
Canvas.CopyRect(rc, offscreenBitmap.Canvas, | |
Rect(rc.Left, rc.Top - ToolBar1.Height, rc.Right, rc.Bottom - ToolBar1.Height)); | |
end | |
else | |
begin | |
Canvas.Brush.Color := clBlack; | |
Canvas.FillRect(Rect(0, 0, ClientWidth - 1, ClientHeight - StatusBar1.Height - 1)); | |
end; | |
end; | |
procedure TAnalogFrm.FormMouseMove(Sender: TObject; Shift: TShiftState; X, | |
Y: Integer); | |
var currentCh: integer; | |
iX, iY: integer; | |
begin | |
currentCh := 3; iX := 0; iY := 0; | |
with mpFile do | |
if not AnalogChEnabled[2] and not AnalogChEnabled[3] then Exit; | |
with mpFile do | |
begin | |
if AnalogChEnabled[2] and not AnalogChEnabled[3] then | |
begin | |
currentCh := 3; | |
iX := MulDiv(X, ChDataPtsPerFrame[2] - 1, ch2Rect.Right - ch2Rect.Left); | |
iY := MulDiv(Y - ch2Rect.Top, - 2 * f_MAX_Y_VALUE - 1, ch2Rect.Bottom - ch2Rect.Top) | |
+ f_MAX_Y_VALUE; | |
end; | |
if not AnalogChEnabled[2] and AnalogChEnabled[3] then | |
begin | |
currentCh := 4; | |
iX := MulDiv(X, ChDataPtsPerFrame[3] - 1, ch3Rect.Right - ch3Rect.Left); | |
iY := MulDiv(Y - ch3Rect.Top, - 2 * f_MAX_Y_VALUE - 1, ch3Rect.Bottom - ch3Rect.Top) | |
+ f_MAX_Y_VALUE; | |
end; | |
if AnalogChEnabled[2] and AnalogChEnabled[3] then | |
begin | |
if X < ClientWidth div 2 then | |
currentCh := 3 | |
else | |
begin | |
currentCh := 4; | |
X := X - ClientWidth div 2 - 1; | |
end; | |
if currentCh = 3 then | |
begin | |
iX := MulDiv(X, ChDataPtsPerFrame[2] - 1, ch2Rect.Right - ch2Rect.Left); | |
iY := MulDiv(Y - ch2Rect.Top, - 2 * f_MAX_Y_VALUE - 1, ch2Rect.Bottom - ch2Rect.Top) | |
+ f_MAX_Y_VALUE; | |
end | |
else | |
begin | |
iX := MulDiv(X, ChDataPtsPerFrame[3] - 1, ch3Rect.Right - ch3Rect.Left); | |
iY := MulDiv(Y - ch3Rect.Top, - 2 * f_MAX_Y_VALUE - 1, ch3Rect.Bottom - ch3Rect.Top) | |
+ f_MAX_Y_VALUE; | |
end; | |
end; | |
StatusBar1.Panels[1].Text := 'Analog Ch' + IntToStr(currentCh - 2) + ': ' + mpFile.ChNames[currentCh - 1]; | |
StatusBar1.Panels[2].Text := 'T: ' + AnalogXToTime(currentCh - 1 {zero-based}, iX); | |
StatusBar1.Panels[3].Text := 'Analog: ' + AnalogYToValue(currentCh - 1 {zero-based}, iY); | |
end; | |
end; | |
procedure TAnalogFrm.FormResize(Sender: TObject); | |
begin | |
ResizeElements; | |
Invalidate; {necessary?} | |
StatusBar1.Panels[0].Text := 'Frame: ' + IntToStr(CurrentFrameIndex + 1) + | |
'/' + IntToStr(mpFile.FrameCount); | |
end; | |
{-------------------------------- MENU EVENTS ---------------------------------} | |
procedure TAnalogFrm.ToolButton1Click(Sender: TObject); | |
begin | |
while (CurrentFrameIndex > 0) and (ToolButton1.Down) do | |
begin | |
CurrentFrameIndex := CurrentFrameIndex - 1; | |
Application.ProcessMessages; | |
end; | |
ToolButton1.Down := False; | |
end; | |
procedure TAnalogFrm.ToolButton2Click(Sender: TObject); | |
begin | |
CurrentFrameIndex := CurrentFrameIndex - 1; | |
end; | |
procedure TAnalogFrm.ToolButton3Click(Sender: TObject); | |
begin | |
ToolButton1.Down := False; | |
ToolButton5.Down := False; | |
end; | |
procedure TAnalogFrm.ToolButton4Click(Sender: TObject); | |
begin | |
CurrentFrameIndex := CurrentFrameIndex + 1; | |
end; | |
procedure TAnalogFrm.ToolButton5Click(Sender: TObject); | |
begin | |
while (CurrentFrameIndex < mpFile.FrameCount - 1) and (ToolButton5.Down) do | |
begin | |
CurrentFrameIndex := CurrentFrameIndex + 1; | |
Application.ProcessMessages; | |
end; | |
ToolButton5.Down := False; | |
end; | |
procedure TAnalogFrm.FirstFrame1Click(Sender: TObject); | |
begin | |
CurrentFrameIndex := 0; | |
end; | |
procedure TAnalogFrm.LastFrame1Click(Sender: TObject); | |
begin | |
CurrentFrameIndex := mpFile.FrameCount - 1; | |
end; | |
procedure TAnalogFrm.GotoFrame1Click(Sender: TObject); | |
var s: string; | |
newFrameIndex: integer; | |
begin | |
s := '1'; | |
if InputQuery('Go to Frame', 'Enter Frame Index', s) then | |
try | |
newFrameIndex := StrToInt(s); | |
if (newFrameIndex > 0) and (newFrameIndex <= mpFile.FrameCount) then | |
CurrentFrameIndex := newFrameIndex - 1 | |
else | |
MessageDlg('Frame Index Out of Bounds.', mtError, [mbOK], 0); | |
except | |
MessageDlg('Invalid Frame Index.', mtError, [mbOK], 0); | |
end; | |
end; | |
procedure TAnalogFrm.CopytoBitmap1Click(Sender: TObject); | |
begin | |
with Clipboard do | |
begin | |
Open; | |
Assign(offscreenBitmap); | |
Close; | |
end; | |
end; | |
procedure TAnalogFrm.CopyDatatoClipboard1Click(Sender: TObject); | |
var fromFrame, toFrame: integer; | |
savedCursor: TCursor; | |
begin | |
with CopyAnalogDlg do | |
begin | |
RadioButton1.Checked := mpFile.AnalogChEnabled[2]; | |
RadioButton1.Enabled := mpFile.AnalogChEnabled[2]; | |
RadioButton2.Checked := mpFile.AnalogChEnabled[3]; | |
RadioButton2.Enabled := mpFile.AnalogChEnabled[3]; | |
SpinEdit1.Value := CurrentFrameIndex + 1; | |
SpinEdit2.Value := CurrentFrameIndex + 1; | |
if CopyAnalogDlg.ShowModal = mrOK then | |
begin | |
fromFrame := SpinEdit1.Value - 1; | |
toFrame := SpinEdit2.Value - 1; | |
if (fromFrame >= 0) and (fromFrame <= mpFile.FrameCount - 1) and | |
(toFrame >= 0) and (toFrame <= mpFile.FrameCount - 1) and | |
(fromFrame <= toFrame) then | |
begin | |
savedCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
mpFile.CopyChannelsToClipboard( | |
RadioButton1.Checked and RadioButton1.Enabled, | |
RadioButton2.Checked and RadioButton2.Enabled, | |
fromFrame, toFrame); | |
finally | |
Screen.Cursor := savedCursor; | |
end; | |
end | |
else | |
MessageDlg('Invalid frame indices.', mtError, [mbOK], 0); | |
end; | |
end; | |
end; | |
procedure TAnalogFrm.Axes1Click(Sender: TObject); | |
var newYTop2, newYExtent2, newYTop3, newYExtent3: integer; | |
bAccepted: boolean; | |
begin | |
newyTop2 := 0; | |
newyTop3 := 0; | |
newyExtent2 := 0; | |
newyExtent3 := 0; | |
with AnYAxisDlg do | |
begin | |
if mpFile.AnalogChEnabled[2] then | |
begin | |
PhysUnitEdit1.PhysUnit := mpFile.ChUnit[2]; | |
PhysUnitEdit1.ConvFactor := mpFile.ChConvFactor[2]; | |
PhysUnitEdit1.Prefix := PrefixToExponent(mpFile.ChPrefix[2]); | |
PhysUnitEdit1.PhysOffset := mpFile.ChOffset[2]; | |
PhysUnitEdit2.PhysUnit := mpFile.ChUnit[2]; | |
PhysUnitEdit2.ConvFactor := mpFile.ChConvFactor[2]; | |
PhysUnitEdit2.Prefix := PrefixToExponent(mpFile.ChPrefix[2]); | |
PhysUnitEdit2.PhysOffset := mpFile.ChOffset[2]; | |
PhysUnitEdit1.int16Value := yTop2; | |
PhysUnitEdit2.int16Value := yTop2 - yExtent2 + 1; | |
end; | |
if mpFile.AnalogChEnabled[3] then | |
begin | |
PhysUnitEdit3.PhysUnit := mpFile.ChUnit[3]; | |
PhysUnitEdit3.ConvFactor := mpFile.ChConvFactor[3]; | |
PhysUnitEdit3.Prefix := PrefixToExponent(mpFile.ChPrefix[3]); | |
PhysUnitEdit3.PhysOffset := mpFile.ChOffset[3]; | |
PhysUnitEdit4.PhysUnit := mpFile.ChUnit[3]; | |
PhysUnitEdit4.ConvFactor := mpFile.ChConvFactor[3]; | |
PhysUnitEdit4.Prefix := PrefixToExponent(mpFile.ChPrefix[3]); | |
PhysUnitEdit4.PhysOffset := mpFile.ChOffset[3]; | |
PhysUnitEdit3.int16Value := yTop3; | |
PhysUnitEdit4.int16Value := yTop3 - yExtent3 + 1; | |
end; | |
TabSheet1.Enabled := mpFile.AnalogChEnabled[2]; | |
TabSheet2.Enabled := mpFile.AnalogChEnabled[3]; | |
if not mpFile.AnalogChEnabled[2] then PageControl1.ActivePage := TabSheet2 | |
else PageControl1.ActivePage := TabSheet1; | |
end; | |
if AnYAxisDlg.ShowModal = mrOK then | |
with AnYAxisDlg do | |
begin | |
bAccepted := True; | |
if mpFile.AnalogChEnabled[2] then | |
begin | |
newyTop2 := PhysUnitEdit1.int16Value; | |
newyExtent2 := newyTop2 - PhysUnitEdit2.int16Value + 1; | |
if (newyTop2 > f_MAX_Y_VALUE) or (newyTop2 < -(f_MAX_Y_VALUE + 1)) or | |
(newyExtent2 < 10) or (newyExtent2 > 2 * (f_MAX_Y_VALUE + 1)) then | |
bAccepted := False; | |
end; | |
if mpFile.AnalogChEnabled[3] then | |
begin | |
newyTop3 := PhysUnitEdit3.int16Value; | |
newyExtent3 := newyTop3 - PhysUnitEdit4.int16Value + 1; | |
if (newyTop3 > f_MAX_Y_VALUE) or (newyTop3 < -(f_MAX_Y_VALUE + 1)) or | |
(newyExtent3 < 10) or (newyExtent3 > 2 * (f_MAX_Y_VALUE + 1)) then | |
bAccepted := False; | |
end; | |
if bAccepted then | |
begin | |
yTop2 := newyTop2; | |
yTop3 := newyTop3; | |
yExtent2 := newyExtent2; | |
yExtent3 := newyExtent3; | |
DrawAnalogData; | |
end | |
else | |
MessageDlg('Invalid Y Axes Values.', mtError, [mbOK], 0); | |
end; | |
end; | |
procedure TAnalogFrm.NewAnalogChannelsWindow1Click(Sender: TObject); | |
begin | |
mpFile.NewAnalogWnd; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit AVIOptDlgu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
StdCtrls, Buttons, Spin, ExtCtrls, MPFileu; | |
type | |
TAVIOptDlg = class(TForm) | |
Label1: TLabel; | |
SpinEdit1: TSpinEdit; | |
Label3: TLabel; | |
SpinEdit2: TSpinEdit; | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
Bevel1: TBevel; | |
Label2: TLabel; | |
SpinEdit3: TSpinEdit; | |
Label4: TLabel; | |
GroupBox1: TGroupBox; | |
RadioButton1: TRadioButton; | |
RadioButton3: TRadioButton; | |
RadioButton2: TRadioButton; | |
RadioButton4: TRadioButton; | |
GroupBox2: TGroupBox; | |
RadioButton5: TRadioButton; | |
RadioButton6: TRadioButton; | |
RadioButton7: TRadioButton; | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
procedure InitGUI(afile: TMPFile); | |
function SelectedCh: integer; | |
end; | |
var | |
AVIOptDlg: TAVIOptDlg; | |
implementation | |
{$R *.DFM} | |
procedure TAVIOptDlg.InitGUI(afile: TMPFile); | |
begin | |
with afile do | |
begin | |
RadioButton1.Checked := (DefaultVideoChannel = 0); | |
RadioButton2.Checked := (DefaultVideoChannel = 1); | |
RadioButton3.Checked := (DefaultVideoChannel = 2); | |
RadioButton4.Checked := (DefaultVideoChannel = 3); | |
if VideoChCount = 1 then | |
begin | |
RadioButton1.Enabled := False; | |
RadioButton2.Enabled := False; | |
RadioButton3.Enabled := False; | |
RadioButton4.Enabled := False; | |
end | |
else | |
begin | |
RadioButton1.Enabled := ChEnabled[0]; | |
RadioButton2.Enabled := ChEnabled[1]; | |
RadioButton3.Enabled := ChEnabled[2]; | |
RadioButton4.Enabled := ChEnabled[3]; | |
end; | |
end; | |
end; | |
function TAVIOptDlg.SelectedCh: integer; | |
begin | |
if RadioButton1.Checked then | |
Result := 0 | |
else if RadioButton2.Checked then | |
Result := 1 | |
else if RadioButton3.Checked then | |
Result := 2 | |
else if RadioButton4.Checked then | |
Result := 3 | |
else | |
Result := 0; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit Avgthreadu; | |
interface | |
uses | |
Classes, Mainfrm; | |
type | |
TAvgThread = class(TThread) | |
private | |
procedure UpdateAverage; | |
protected | |
procedure Execute; override; | |
public | |
constructor Create(CreateSuspended: Boolean); | |
end; | |
implementation | |
{ Important: Methods and properties of objects in VCL can only be used in a | |
method called using Synchronize, for example, | |
Synchronize(UpdateCaption); | |
and UpdateCaption could look like, | |
procedure TAvgThread.UpdateCaption; | |
begin | |
Form1.Caption := 'Updated in a thread'; | |
end; } | |
{ TAvgThread } | |
uses AvgFrmu, MPUnit, Windows; | |
procedure TAvgThread.UpdateAverage; | |
begin | |
AvgFrm.BlastFrame; | |
end; | |
constructor TAvgThread.Create(CreateSuspended: Boolean); | |
begin | |
AvgFrm.curAvgCount := 0; | |
inherited Create(CreateSuspended); | |
FreeOnTerminate := True; | |
end; | |
procedure TAvgThread.Execute; | |
var i, j: integer; | |
begin | |
{ Place thread code here } | |
with AvgFrm do | |
begin | |
{ ReleaseMutex(avgThreadMutex);} {initializes Mutex} | |
repeat | |
{Wait indefinitely for data} | |
if WaitForSingleObject(avgThreadSemaphore, INFINITE) = WAIT_OBJECT_0 then | |
{We have data - hold and copy} | |
if WaitForSingleObject(avgThreadMutex, INFINITE) = WAIT_OBJECT_0 then | |
if framesDisplayed > lastFrameDisplayed then | |
begin | |
for j := 0 to MAX_CH - 1 do | |
if Mainform.Configuration.VideoChEnabled[j] then | |
if cbAvgFrameSize[j] > 0 then | |
System.Move(pTempAvgFrameData[j]^[0], | |
pLastFrameData[j]^[0], cbAvgFrameSize[j]); | |
ReleaseMutex(avgThreadMutex); | |
for j := 0 to MAX_CH - 1 do | |
if Mainform.Configuration.VideoChEnabled[j] then | |
if cbAvgFrameSize[j] > 0 then | |
begin | |
if (curAvgCount = 0) and (lastFrameDisplayed > 0) then | |
{zero the averages} | |
FillChar(pAvgFrameData[j]^, cbAvgFrameSize[j], 0); | |
for i := 0 to cbAvgFrameSize[j] div SizeOf(int16) - 1 do | |
pAvgFrameData[j]^[i] := pAvgFrameData[j]^[i] + pLastFrameData[j]^[i]; | |
end; | |
lastFrameDisplayed := framesDisplayed; | |
curAvgCount := curAvgCount + 1; | |
if curAvgCount >= AvgFrm.SpinEdit1.Value then | |
begin | |
for j := 0 to MAX_CH - 1 do | |
if Mainform.Configuration.VideoChEnabled[j] then | |
if cbAvgFrameSize[j] > 0 then | |
for i := 0 to cbAvgFrameSize[j] div SizeOf(int16) - 1 do | |
if Mainform.configuration.PhotonCountingEnabled[j] then | |
// photon counting will be a sum, not an average | |
pAvgFrameData[j]^[i] := pAvgFrameData[j]^[i] | |
else | |
// analog - use an average | |
pAvgFrameData[j]^[i] := pAvgFrameData[j]^[i] div curAvgCount; | |
// note - the display of the values contained in pAvgFrameData happens in | |
// TAvgfrm.MakeBitmap | |
Synchronize(UpdateAverage); | |
curAvgCount := 0; | |
end; | |
end | |
else | |
ReleaseMutex(avgThreadMutex); | |
until Terminated or not Mainform.Scanning; | |
end; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit anyaxisu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
StdCtrls, Physuedt, Buttons, ComCtrls; | |
type | |
TAnYAxisDlg = class(TForm) | |
PageControl1: TPageControl; | |
TabSheet1: TTabSheet; | |
Label1: TLabel; | |
Label2: TLabel; | |
TabSheet2: TTabSheet; | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
PhysUnitEdit1: TPhysUnitEdit; | |
PhysUnitEdit2: TPhysUnitEdit; | |
Label3: TLabel; | |
PhysUnitEdit3: TPhysUnitEdit; | |
Label4: TLabel; | |
PhysUnitEdit4: TPhysUnitEdit; | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
end; | |
var | |
AnYAxisDlg: TAnYAxisDlg; | |
implementation | |
{$R *.DFM} | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit binfrm; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
ExtCtrls, StdCtrls, Buttons, ComCtrls, Spin; | |
type | |
TBinOpForm = class(TForm) | |
GroupBox1: TGroupBox; | |
Label1: TLabel; | |
Label2: TLabel; | |
Label3: TLabel; | |
ComboBox1: TComboBox; | |
SpinEdit1: TSpinEdit; | |
Edit1: TEdit; | |
TrackBar1: TTrackBar; | |
BitBtn1: TBitBtn; | |
GroupBox2: TGroupBox; | |
Label4: TLabel; | |
Label5: TLabel; | |
Label6: TLabel; | |
ComboBox2: TComboBox; | |
SpinEdit2: TSpinEdit; | |
Edit2: TEdit; | |
TrackBar2: TTrackBar; | |
GroupBox3: TGroupBox; | |
Label7: TLabel; | |
ComboBox3: TComboBox; | |
Label8: TLabel; | |
Bevel1: TBevel; | |
Label9: TLabel; | |
SpeedButton1: TSpeedButton; | |
BitBtn2: TBitBtn; | |
RadioButton1: TRadioButton; | |
RadioButton2: TRadioButton; | |
RadioButton3: TRadioButton; | |
RadioButton4: TRadioButton; | |
RadioButton5: TRadioButton; | |
RadioButton6: TRadioButton; | |
RadioButton7: TRadioButton; | |
RadioButton8: TRadioButton; | |
procedure BitBtn1Click(Sender: TObject); | |
procedure FormClose(Sender: TObject; var Action: TCloseAction); | |
procedure FormCreate(Sender: TObject); | |
procedure TrackBar2Change(Sender: TObject); | |
procedure TrackBar1Change(Sender: TObject); | |
procedure ComboBox1Change(Sender: TObject); | |
procedure ComboBox2Change(Sender: TObject); | |
procedure FormShow(Sender: TObject); | |
procedure SpeedButton1Click(Sender: TObject); | |
procedure BitBtn2Click(Sender: TObject); | |
private | |
{ Private declarations } | |
function Frames12Compatible: boolean; | |
function Frames123Compatible: boolean; | |
public | |
{ Public declarations } | |
resultFrameIndex: integer; | |
end; | |
var | |
BinOpForm: TBinOpForm; | |
implementation | |
{$R *.DFM} | |
Uses Mainfrm, MPViewu, MPFileu; | |
function TBinOpForm.Frames12Compatible: boolean; | |
var file1, file2: TMPFile; | |
begin | |
file1 := TMPFile(ComboBox1.Items.Objects[ComboBox1.ItemIndex]); | |
file2 := TMPFile(ComboBox2.Items.Objects[ComboBox2.ItemIndex]); | |
Result := (file1.Resolution = file2.Resolution) and | |
(file1.FrameWidth = file2.FrameWidth) and | |
(file1.FrameHeight = file2.FrameHeight); | |
end; | |
function TBinOpForm.Frames123Compatible: boolean; | |
var file1, file2, resultFile: TMPFile; | |
frame1, frame2: integer; | |
begin | |
file1 := TMPFile(ComboBox1.Items.Objects[ComboBox1.ItemIndex]); | |
file2 := TMPFile(ComboBox2.Items.Objects[ComboBox2.ItemIndex]); | |
resultFile := TMPFile(ComboBox3.Items.Objects[ComboBox3.ItemIndex]); | |
frame1 := SpinEdit1.Value - 1; | |
frame2 := SpinEdit2.Value - 1; | |
Result := Frames12Compatible and | |
(resultFrameIndex <> -1) and | |
// (resultFile.Resolution = file1.Resolution) and | |
(resultFile.FrameWidth = file1.FrameWidth) and | |
(resultFile.FrameHeight = file1.FrameHeight) and | |
(frame1 >= 0) and (frame1 < file1.FrameCount) and | |
(frame2 >= 0) and (frame2 < file2.FrameCount) and | |
(resultFrameIndex >= 0) and (resultFrameIndex < resultFile.FrameCount); | |
end; | |
procedure TBinOpForm.BitBtn1Click(Sender: TObject); | |
begin | |
Close; | |
end; | |
procedure TBinOpForm.FormClose(Sender: TObject; var Action: TCloseAction); | |
begin | |
Mainform.bBinaryOp := False; | |
Action := caFree; | |
end; | |
procedure TBinOpForm.FormCreate(Sender: TObject); | |
var i: integer; | |
s: string; | |
begin | |
resultFrameIndex := -1; | |
for i := 0 to Mainform.fileList.Count - 1 do | |
begin | |
s := Mainform.fileList.Strings[i]; | |
if not TMPFile(Mainform.fileList.Objects[i]).IsMemoryFile then | |
s := ExtractFileName(s); | |
ComboBox1.Items.AddObject(s, Mainform.fileList.Objects[i]); | |
ComboBox2.Items.AddObject(s, Mainform.fileList.Objects[i]); | |
if TMPFile(Mainform.fileList.Objects[i]).IsMemoryFile then | |
ComboBox3.Items.AddObject(s, Mainform.fileList.Objects[i]); | |
end; | |
ComboBox1.ItemIndex := 0; | |
ComboBox2.ItemIndex := 0; | |
ComboBox3.ItemIndex := 0; | |
end; | |
procedure TBinOpForm.TrackBar2Change(Sender: TObject); | |
begin | |
Edit2.Text := FloatToStr(TrackBar2.Position / 10); | |
end; | |
procedure TBinOpForm.TrackBar1Change(Sender: TObject); | |
begin | |
Edit1.Text := FloatToStr(TrackBar1.Position / 10); | |
end; | |
procedure TBinOpForm.ComboBox1Change(Sender: TObject); | |
begin | |
if ComboBox1.ItemIndex >= 0 then | |
with TMPFile(ComboBox1.Items.Objects[ComboBox1.ItemIndex]) do | |
begin | |
RadioButton1.Checked := (DefaultVideoChannel = 0); | |
RadioButton2.Checked := not (DefaultVideoChannel = 1); | |
RadioButton5.Checked := not (DefaultVideoChannel = 2); | |
RadioButton6.Checked := not (DefaultVideoChannel = 3); | |
if VideoChCount = 1 then | |
begin | |
RadioButton1.Enabled := False; | |
RadioButton2.Enabled := False; | |
RadioButton5.Enabled := False; | |
RadioButton6.Enabled := False; | |
end | |
else | |
begin | |
RadioButton1.Enabled := VideoChEnabled[0]; | |
RadioButton2.Enabled := VideoChEnabled[1]; | |
RadioButton5.Enabled := VideoChEnabled[2]; | |
RadioButton6.Enabled := VideoChEnabled[3]; | |
end; | |
end; | |
end; | |
procedure TBinOpForm.ComboBox2Change(Sender: TObject); | |
begin | |
if ComboBox2.ItemIndex >= 0 then | |
with TMPFile(ComboBox2.Items.Objects[ComboBox2.ItemIndex]) do | |
begin | |
RadioButton3.Checked := (DefaultVideoChannel = 0); | |
RadioButton4.Checked := not (DefaultVideoChannel = 0); | |
RadioButton7.Checked := not (DefaultVideoChannel = 2); | |
RadioButton8.Checked := not (DefaultVideoChannel = 3); | |
if VideoChCount = 1 then | |
begin | |
RadioButton3.Enabled := False; | |
RadioButton4.Enabled := False; | |
RadioButton7.Enabled := False; | |
RadioButton8.Enabled := False; | |
end | |
else | |
begin | |
RadioButton3.Enabled := VideoChEnabled[0]; | |
RadioButton4.Enabled := VideoChEnabled[1]; | |
RadioButton7.Enabled := VideoChEnabled[2]; | |
RadioButton8.Enabled := VideoChEnabled[3]; | |
end; | |
end; | |
end; | |
procedure TBinOpForm.FormShow(Sender: TObject); | |
begin | |
ComboBox1Change(nil); | |
ComboBox2Change(nil); | |
end; | |
procedure TBinOpForm.SpeedButton1Click(Sender: TObject); | |
var resultFile, file1: TMPFile; | |
begin | |
resultFile := TMPFile(ComboBox3.Items.Objects[ComboBox3.ItemIndex]); | |
file1 := TMPFile(ComboBox1.Items.Objects[ComboBox1.ItemIndex]); | |
{Prerequisitites} | |
if Frames12Compatible then | |
begin | |
ResultFrameIndex := resultFile.CreateEmptyFrame(file1); | |
Label9.Caption := IntToStr(ResultFrameIndex + 1); | |
end | |
else | |
MessageDlg('Frame 1 and Frame 2 are incompatible.', mtError, [mbOK], 0); | |
end; | |
procedure TBinOpForm.BitBtn2Click(Sender: TObject); | |
var file1, file2, resultFile: TMPFile; | |
ch1, ch2, frame1, frame2: integer; | |
gain1, gain2: double; | |
begin | |
file1 := TMPFile(ComboBox1.Items.Objects[ComboBox1.ItemIndex]); | |
file2 := TMPFile(ComboBox2.Items.Objects[ComboBox2.ItemIndex]); | |
resultFile := TMPFile(ComboBox3.Items.Objects[ComboBox3.ItemIndex]); | |
frame1 := SpinEdit1.Value - 1; | |
frame2 := SpinEdit2.Value - 1; | |
if RadioButton1.Checked then | |
ch1 := 0 | |
else if RadioButton2.Checked then | |
ch1 := 1 | |
else if RadioButton5.Checked then | |
ch1 := 2 | |
else | |
ch1 := 3; | |
if RadioButton3.Checked then | |
ch2 := 0 | |
else if RadioButton4.Checked then | |
ch2 := 1 | |
else if RadioButton7.Checked then | |
ch2 := 2 | |
else | |
ch2 := 3; | |
gain1 := StrToFloat(Edit1.Text); | |
gain2 := StrToFloat(Edit2.Text); | |
if Frames123Compatible then | |
resultFile.BinaryOp(file1, file2, ch1, ch2, frame1, frame2, gain1, gain2, resultFrameIndex) | |
else | |
MessageDlg('Invalid binary operation parameter(s).', mtError, [mbOK], 0); | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit cpmdlgu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
Spin, StdCtrls, Buttons; | |
type | |
TCopyToMatlabDlg = class(TForm) | |
Label1: TLabel; | |
Label2: TLabel; | |
Label3: TLabel; | |
Label4: TLabel; | |
Edit1: TEdit; | |
RadioButton1: TRadioButton; | |
Label5: TLabel; | |
Label6: TLabel; | |
Edit2: TEdit; | |
RadioButton2: TRadioButton; | |
SpinEdit1: TSpinEdit; | |
SpinEdit2: TSpinEdit; | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
end; | |
var | |
CopyToMatlabDlg: TCopyToMatlabDlg; | |
implementation | |
{$R *.DFM} | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit cpymdlg; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
ExtCtrls, StdCtrls, Buttons, Spin; | |
type | |
TCopymdlg = class(TForm) | |
Label1: TLabel; | |
Label2: TLabel; | |
Label4: TLabel; | |
Edit1: TEdit; | |
Edit2: TEdit; | |
SpinEdit1: TSpinEdit; | |
SpinEdit2: TSpinEdit; | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
Bevel1: TBevel; | |
RadioButton1: TRadioButton; | |
RadioButton2: TRadioButton; | |
Label3: TLabel; | |
Label5: TLabel; | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
end; | |
var | |
Copymdlg: TCopymdlg; | |
implementation | |
{$R *.DFM} | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit DMCCom40u; | |
interface | |
{ Windows interface to Galil Motion Controllers | |
' For Delphi 5 and higher | |
' All functions return an error code. 0 is function completed successfully. | |
' Any error code < 0 is a local error (see the error codes belong). | |
' Any error code > 0 is an Win32 API error. | |
' These are documented in the Win32 Programming Reference. | |
' Constant values | |
} | |
const | |
DMC400 = 'DMC-400'; | |
DMC600 = 'DMC-600'; | |
DMC700 = 'DMC-700'; | |
DMC1000 = 'DMC-1000'; | |
DMC1200 = 'DMC-1200'; | |
DMC1410 = 'DMC-1410'; | |
DMC1411 = 'DMC-1411'; | |
DMC1412 = 'DMC-1412'; | |
DMC1417 = 'DMC-1417'; | |
DMC1500 = 'DMC-1500'; | |
DMC1600 = 'DMC-1600'; | |
DMC1700 = 'DMC-1700'; | |
DMC1800 = 'DMC-1800'; | |
DMC1802 = 'DMC-1802'; | |
DMC2000 = 'DMC-2000'; | |
DMC2100 = 'DMC-2100'; | |
DMC90064 = 'IOC-90064'; | |
// Error Codes | |
DMCNOERROR = 0; | |
DMCERROR_TIMEOUT = -1; | |
DMCERROR_COMMAND = -2; | |
DMCERROR_CONTROLLER = -3; | |
DMCERROR_FILE = -4; | |
DMCERROR_DRIVER = -5 ; | |
DMCERROR_HANDLE = -6; | |
DMCERROR_HMODULE = -7; | |
DMCERROR_MEMORY = -8; | |
DMCERROR_BUFFERFULL = -9; | |
DMCERROR_RESPONSEDATA = -10; | |
DMCERROR_DMA = -11; | |
DMCERROR_ARGUMENT = -12; | |
DMCERROR_DATARECORD = -13; | |
DMCERROR_DOWNLOAD = -14; | |
DMCERROR_FIRMWARE = -15; | |
DMCERROR_CONVERSION = -16; | |
DMCERROR_RESOURCE = -17; | |
DMCERROR_REGISTRY = -18; | |
DMCERROR_BUSY = -19; | |
DMCERROR_DEVICE_DISCONNECTED = -20; | |
{' IMPORTANT: Constant values for data record item offsets can change between | |
' firmware revisions. Use the QZ command or the function DMCGetDataRecordRevision | |
' to determine what revision of data record access you have. | |
' The DMCGetDataRecordByItemId function retrieves a data record item by unique | |
' Id while the DMCGetDataRecord function retrieves a data record item by offset. | |
' While data record item offsets can change with the firmware revision, the data | |
' record item Ids always remain the same. | |
' Constant values for data record data types} | |
DRTypeUnknown = 0; | |
DRTypeCHAR = 1; | |
DRTypeUCHAR = 2; | |
DRTypeSHORT = 3; | |
DRTypeUSHORT = 4; | |
DRTypeLONG = 5; | |
DRTypeULONG = 6; | |
{' Constant values for data record item Ids to be used with the function | |
' DMCGetDataRecordByItemId} | |
DRIdSampleNumber = 1; | |
DRIdGeneralInput0 = 2; | |
DRIdGeneralInput1 = 3; | |
DRIdGeneralInput2 = 4; | |
DRIdGeneralInput3 = 5; | |
DRIdGeneralInput4 = 6; | |
DRIdGeneralInput5 = 7; | |
DRIdGeneralInput6 = 8; | |
DRIdGeneralInput7 = 9; | |
DRIdGeneralInput8 = 10; | |
DRIdGeneralInput9 = 11; | |
DRIdGeneralOutput0 = 12; | |
DRIdGeneralOutput1 = 13; | |
DRIdGeneralOutput2 = 14; | |
DRIdGeneralOutput3 = 15; | |
DRIdGeneralOutput4 = 16; | |
DRIdGeneralOutput5 = 17; | |
DRIdGeneralOutput6 = 18; | |
DRIdGeneralOutput7 = 19; | |
DRIdGeneralOutput8 = 20; | |
DRIdGeneralOutput9 = 21; | |
DRIdErrorCode = 22; | |
DRIdGeneralStatus = 23; | |
DRIdSegmentCountS = 24; | |
DRIdCoordinatedMoveStatusS = 25; | |
DRIdCoordinatedMoveDistanceS = 26; | |
DRIdSegmentCountT = 27; | |
DRIdCoordinatedMoveStatusT = 28; | |
DRIdCoordinatedMoveDistanceT = 29; | |
DRIdAnalogInput1 = 30; | |
DRIdAnalogInput2 = 31; | |
DRIdAnalogInput3 = 32; | |
DRIdAnalogInput4 = 33; | |
DRIdAnalogInput5 = 34; | |
DRIdAnalogInput6 = 35; | |
DRIdAnalogInput7 = 36; | |
DRIdAnalogInput8 = 37; | |
DRIdAxisStatus = 38; | |
DRIdAxisSwitches = 39; | |
DRIdAxisStopCode = 40; | |
DRIdAxisReferencePosition = 41; | |
DRIdAxisMotorPosition = 42; | |
DRIdAxisPositionError = 43; | |
DRIdAxisAuxillaryPosition = 44 ; | |
DRIdAxisVelocity = 45; | |
DRIdAxisTorque = 46; | |
DRIdSlotModulePresent = 47; | |
DRIdSlotModuleType = 48; | |
DRIdSlotNumberOfIOPoints = 49; | |
DRIdSlotIODirection = 50; | |
DRIdSlotAnalogRange = 51; | |
DRIdSlotRangeType = 52; | |
DRIdSlotIOData0 = 53; | |
DRIdSlotIOData1 = 54; | |
DRIdSlotIOData2 = 55; | |
DRIdSlotIOData3 = 56; | |
DRIdSlotIOData4 = 57; | |
DRIdSlotIOData5 = 58; | |
DRIdSlotIOData6 = 59; | |
DRIdSlotIOData7 = 60; | |
{' Constant values for axis Ids to be used with the function | |
' DMCGetDataRecordByItemId} | |
DRIdAxis1 = 1; | |
DRIdAxis2 = 2; | |
DRIdAxis3 = 3; | |
DRIdAxis4 = 4; | |
DRIdAxis5 = 5; | |
DRIdAxis6 = 6; | |
DRIdAxis7 = 7; | |
DRIdAxis8 = 8; | |
{'Constant values for IOC7007 slot Ids to be used with the function | |
'DMCGetDataRecordByItemId | |
'DMCGetDataRecordSlotIDs} | |
DRIdSlot1 = 15; | |
DRIdSlot2 = 16; | |
DRIdSlot3 = 17; | |
DRIdSlot4 = 18; | |
DRIdSlot5 = 19; | |
DRIdSlot6 = 20; | |
DRIdSlot7 = 21; | |
{' Data record offsets | |
' Rev 1 constants | |
' QZ command returns <#axes>,12,6,26 | |
' Rev 2 constants | |
' QZ command returns <#axes>,26,6,26 | |
' This rev added items to the general section for extended I/O. | |
' Rev 3 constants | |
' QZ command returns <#axes>,24,16,26 | |
' This rev added items to the general section for the coordinated motion T axis. | |
' Rev 4 constants | |
' QZ command returns <#axes>,24,16,28 | |
' This rev added 1 item to the axis section for analog inputs. | |
' Note: each axis will now include the current value for 1 analog input. | |
' X axis - analog 1, Y axis - analog 2, and so on. You must have an 8 axis | |
' controller to get data for all 8 analog inputs. | |
' Rev 5 constants | |
' QZ command returns 0,8,0,0 | |
' This rev added to accomodate the IOC-90064. | |
' Note: this card's data record is much smaller compared | |
' to previous revisions. The sample number, error | |
' code, general status, and 8 general inputs and 8 general | |
' outputs are supported. | |
'Rev 6 constants | |
'STA: Revision added 11/13/01 to support the IOC-7007 | |
'QZ command returns 7,4,0,22 | |
' Rev 1 General data item offsets} | |
REV1GenOffSampleNumber = 0; | |
REV1GenOffGeneralInput1 = 2; | |
REV1GenOffGeneralInput2 = 3 ; | |
REV1GenOffGeneralInput3 = 4 ; | |
REV1GenOffSpare = 5 ; | |
REV1GenOffGeneralOutput1 = 6 ; | |
REV1GenOffGeneralOutput2 = 7 ; | |
REV1GenOffErrorCode = 8 ; | |
REV1GenOffGeneralStatus = 9 ; | |
REV1GenOffSegmentCount = 10 ; | |
REV1GenOffCoordinatedMoveStatus = 12; | |
REV1GenOffCoordinatedMoveDistance = 14; | |
REV1GenOffAxis1 = 18 ; | |
REV1GenOffAxis2 = 44 ; | |
REV1GenOffAxis3 = 70 ; | |
REV1GenOffAxis4 = 96 ; | |
REV1GenOffAxis5 = 122 ; | |
REV1GenOffAxis6 = 148 ; | |
REV1GenOffAxis7 = 174 ; | |
REV1GenOffAxis8 = 200 ; | |
REV1GenOffEnd = 226 ; | |
{' Rev 1 axis data item offsets} | |
REV1AxisOffNoAxis = 0; | |
REV1AxisOffAxisStatus = 0; | |
REV1AxisOffAxisSwitches = 2; | |
REV1AxisOffAxisStopCode = 3; | |
REV1AxisOffAxisReferencePosition = 4; | |
REV1AxisOffAxisMotorPosition = 8; | |
REV1AxisOffAxisPositionError = 12; | |
REV1AxisOffAxisAuxillaryPosition = 16; | |
REV1AxisOffAxisVelocity = 20; | |
REV1AxisOffAxisTorque = 24; | |
REV1AxisOffEnd = 26; | |
{' Rev 2 General data item offsets} | |
REV2GenOffSampleNumber = 0; | |
REV2GenOffGeneralInput0 = 2; | |
REV2GenOffGeneralInput1 = 3; | |
REV2GenOffGeneralInput2 = 4; | |
REV2GenOffGeneralInput3 = 5; | |
REV2GenOffGeneralInput4 = 6; | |
REV2GenOffGeneralInput5 = 7; | |
REV2GenOffGeneralInput6 = 8; | |
REV2GenOffGeneralInput7 = 9; | |
REV2GenOffGeneralInput8 = 10; | |
REV2GenOffGeneralInput9 = 11; | |
REV2GenOffGeneralOutput0 = 12; | |
REV2GenOffGeneralOutput1 = 13; | |
REV2GenOffGeneralOutput2 = 14; | |
REV2GenOffGeneralOutput3 = 15; | |
REV2GenOffGeneralOutput4 = 16; | |
REV2GenOffGeneralOutput5 = 17; | |
REV2GenOffGeneralOutput6 = 18; | |
REV2GenOffGeneralOutput7 = 19; | |
REV2GenOffGeneralOutput8 = 20; | |
REV2GenOffGeneralOutput9 = 21; | |
REV2GenOffErrorCode = 22; | |
REV2GenOffGeneralStatus = 23; | |
REV2GenOffSegmentCount = 24; | |
REV2GenOffCoordinatedMoveStatus = 26; | |
REV2GenOffCoordinatedMoveDistance = 28; | |
REV2GenOffAxis1 = 32; | |
REV2GenOffAxis2 = 58; | |
REV2GenOffAxis3 = 84; | |
REV2GenOffAxis4 = 110; | |
REV2GenOffAxis5 = 136; | |
REV2GenOffAxis6 = 162; | |
REV2GenOffAxis7 = 188; | |
REV2GenOffAxis8 = 214; | |
REV2GenOffEnd = 240; | |
{' Rev 2 axis data item offsets } | |
REV2AxisOffNoAxis = 0; | |
REV2AxisOffAxisStatus = 0; | |
REV2AxisOffAxisSwitches = 2; | |
REV2AxisOffAxisStopCode = 3; | |
REV2AxisOffAxisReferencePosition = 4; | |
REV2AxisOffAxisMotorPosition = 8; | |
REV2AxisOffAxisPositionError = 12; | |
REV2AxisOffAxisAuxillaryPosition = 16; | |
REV2AxisOffAxisVelocity = 20; | |
REV2AxisOffAxisTorque = 24; | |
REV2AxisOffEnd = 26; | |
{' Rev 3 General data item offsets} | |
REV3GenOffSampleNumber = 0; | |
REV3GenOffGeneralInput0 = 2; | |
REV3GenOffGeneralInput1 = 3; | |
REV3GenOffGeneralInput2 = 4; | |
REV3GenOffGeneralInput3 = 5; | |
REV3GenOffGeneralInput4 = 6; | |
REV3GenOffGeneralInput5 = 7; | |
REV3GenOffGeneralInput6 = 8; | |
REV3GenOffGeneralInput7 = 9; | |
REV3GenOffGeneralInput8 = 10; | |
REV3GenOffGeneralInput9 = 11; | |
REV3GenOffGeneralOutput0 = 12; | |
REV3GenOffGeneralOutput1 = 13; | |
REV3GenOffGeneralOutput2 = 14; | |
REV3GenOffGeneralOutput3 = 15; | |
REV3GenOffGeneralOutput4 = 16; | |
REV3GenOffGeneralOutput5 = 17; | |
REV3GenOffGeneralOutput6 = 18; | |
REV3GenOffGeneralOutput7 = 19; | |
REV3GenOffGeneralOutput8 = 20; | |
REV3GenOffGeneralOutput9 = 21; | |
REV3GenOffErrorCode = 22; | |
REV3GenOffGeneralStatus = 23; | |
REV3GenOffSegmentCountS = 24; | |
REV3GenOffCoordinatedMoveStatusS = 26; | |
REV3GenOffCoordinatedMoveDistanceS = 28; | |
REV3GenOffSegmentCountT = 32; | |
REV3GenOffCoordinatedMoveStatusT = 34; | |
REV3GenOffCoordinatedMoveDistanceT = 36; | |
REV3GenOffAxis1 = 40; | |
REV3GenOffAxis2 = 66; | |
REV3GenOffAxis3 = 92; | |
REV3GenOffAxis4 = 118; | |
REV3GenOffAxis5 = 144; | |
REV3GenOffAxis6 = 170; | |
REV3GenOffAxis7 = 196; | |
REV3GenOffAxis8 = 222; | |
REV3GenOffEnd = 248; | |
{' Rev 3 axis data item offsets} | |
REV3AxisOffNoAxis = 0; | |
REV3AxisOffAxisStatus = 0; | |
REV3AxisOffAxisSwitches = 2; | |
REV3AxisOffAxisStopCode = 3; | |
REV3AxisOffAxisReferencePosition = 4; | |
REV3AxisOffAxisMotorPosition = 8; | |
REV3AxisOffAxisPositionError = 12; | |
REV3AxisOffAxisAuxillaryPosition = 16; | |
REV3AxisOffAxisVelocity = 20; | |
REV3AxisOffAxisTorque = 24; | |
REV3AxisOffEnd = 26; | |
{' Rev 4 General data item offsets} | |
REV4GenOffSampleNumber = 0; | |
REV4GenOffGeneralInput0 = 2; | |
REV4GenOffGeneralInput1 = 3; | |
REV4GenOffGeneralInput2 = 4; | |
REV4GenOffGeneralInput3 = 5; | |
REV4GenOffGeneralInput4 = 6; | |
REV4GenOffGeneralInput5 = 7; | |
REV4GenOffGeneralInput6 = 8; | |
REV4GenOffGeneralInput7 = 9; | |
REV4GenOffGeneralInput8 = 10; | |
REV4GenOffGeneralInput9 = 11; | |
REV4GenOffGeneralOutput0 = 12; | |
REV4GenOffGeneralOutput1 = 13; | |
REV4GenOffGeneralOutput2 = 14; | |
REV4GenOffGeneralOutput3 = 15; | |
REV4GenOffGeneralOutput4 = 16; | |
REV4GenOffGeneralOutput5 = 17; | |
REV4GenOffGeneralOutput6 = 18; | |
REV4GenOffGeneralOutput7 = 19; | |
REV4GenOffGeneralOutput8 = 20; | |
REV4GenOffGeneralOutput9 = 21; | |
REV4GenOffErrorCode = 22; | |
REV4GenOffGeneralStatus = 23; | |
REV4GenOffSegmentCountS = 24; | |
REV4GenOffCoordinatedMoveStatusS = 26; | |
REV4GenOffCoordinatedMoveDistanceS = 28; | |
REV4GenOffSegmentCountT = 32; | |
REV4GenOffCoordinatedMoveStatusT = 34; | |
REV4GenOffCoordinatedMoveDistanceT = 36; | |
REV4GenOffAxis1 = 40; | |
REV4GenOffAxis2 = 68; | |
REV4GenOffAxis3 = 96; | |
REV4GenOffAxis4 = 124; | |
REV4GenOffAxis5 = 152; | |
REV4GenOffAxis6 = 180; | |
REV4GenOffAxis7 = 208; | |
REV4GenOffAxis8 = 236; | |
REV4GenOffEnd = 264; | |
//' Rev 4 axis data item offsets | |
REV4AxisOffNoAxis = 0; | |
REV4AxisOffAxisStatus = 0; | |
REV4AxisOffAxisSwitches = 2; | |
REV4AxisOffAxisStopCode = 3; | |
REV4AxisOffAxisReferencePosition = 4; | |
REV4AxisOffAxisMotorPosition = 8; | |
REV4AxisOffAxisPositionError = 12; | |
REV4AxisOffAxisAuxillaryPosition = 16; | |
REV4AxisOffAxisVelocity = 20; | |
REV4AxisOffAxisTorque = 24; | |
REV4AxisOffAnalogInput = 26; | |
REV4AxisOffEnd = 28 ; | |
//' Rev 5 General data item offsets | |
DRREV5GenOffSampleNumber = 0; | |
DRREV5GenOffConfigByte = 2; | |
DRREV5GenOffGeneralIO0 = 3; | |
DRREV5GenOffGeneralIO1 = 4; | |
DRREV5GenOffGeneralIO2 = 5; | |
DRREV5GenOffGeneralIO3 = 6; | |
DRREV5GenOffGeneralIO4 = 7; | |
DRREV5GenOffGeneralIO5 = 8; | |
DRREV5GenOffGeneralIO6 = 9; | |
DRREV5GenOffGeneralIO7 = 10; | |
DRREV5GenOffErrorCode = 11; | |
DRREV5GenOffGeneralStatus = 12; | |
//' Rev 6 General data item offsets | |
DRREV6GenOffsetSampleNumber = 0; | |
DRREV6GenOffsetErrorCode = 2; | |
DRREV6GenOffsetGeneralStatus = 3; | |
DRREV6GenOffsetSlot1 = 4; | |
DRREV6GenOffsetSlot2 = 26; | |
DRREV6GenOffsetSlot3 = 48; | |
DRREV6GenOffsetSlot4 = 70; | |
DRREV6GenOffsetSlot5 = 92; | |
DRREV6GenOffsetSlot6 = 11; | |
DRREV6GenOffsetSlot7 = 136; | |
DRREV6GenOffsetEnd = 158; | |
{' Rev 6 slot data item offsets | |
' Slots on the IOC7007 are analagous to axis on controllers for the purpose of | |
' data records} | |
DRREV6SlotOffsetModulePresent = 0; | |
DRREV6SlotOffsetDigitalOrAnalogBitCount = 1; | |
DRREV6SlotOffsetNumIOPoints = 2; | |
DRREV6SlotOffsetDirection = 3; | |
DRREV6SlotOffsetRange = 4; | |
DRREV6SlotOffsetRangeType = 5; | |
DRREV6SlotOffsetIOData0 = 6; | |
DRREV6SlotOffsetIOData1 = 8; | |
DRREV6SlotOffsetIOData2 = 10; | |
DRREV6SlotOffsetIOData3 = 12; | |
DRREV6SlotOffsetIOData4 = 14; | |
DRREV6SlotOffsetIOData5 = 16; | |
DRREV6SlotOffsetIOData6 = 18; | |
DRREV6SlotOffsetIOData7 = 20; | |
DRREV6SlotOffsetEnd = 22; | |
{' ** The following constants are OBSOLETE ** | |
' General offsets for firmware without coordinated motion T axis - data record revsion 2} | |
DRGenOffsetsSampleNumber = 0; | |
DRGenOffsetsGeneralInput0 = 2; | |
DRGenOffsetsGeneralInput1 = 3; | |
DRGenOffsetsGeneralInput2 = 4; | |
DRGenOffsetsGeneralInput3 = 5; | |
DRGenOffsetsGeneralInput4 = 6; | |
DRGenOffsetsGeneralInput5 = 7; | |
DRGenOffsetsGeneralInput6 = 8; | |
DRGenOffsetsGeneralInput7 = 9; | |
DRGenOffsetsGeneralInput8 = 10; | |
DRGenOffsetsGeneralInput9 = 11; | |
DRGenOffsetsGeneralOutput0 = 12; | |
DRGenOffsetsGeneralOutput1 = 13; | |
DRGenOffsetsGeneralOutput2 = 14; | |
DRGenOffsetsGeneralOutput3 = 15; | |
DRGenOffsetsGeneralOutput4 = 16; | |
DRGenOffsetsGeneralOutput5 = 17; | |
DRGenOffsetsGeneralOutput6 = 18; | |
DRGenOffsetsGeneralOutput7 = 19; | |
DRGenOffsetsGeneralOutput8 = 20; | |
DRGenOffsetsGeneralOutput9 = 21; | |
DRGenOffsetsErrorCode = 22; | |
DRGenOffsetsGeneralStatus = 23; | |
DRGenOffsetsSegmentCount = 24; | |
DRGenOffsetsCoordinatedMoveStatus = 26; | |
DRGenOffsetsCoordinatedMoveDistance = 28; | |
DRGenOffsetsAxis1 = 32; | |
DRGenOffsetsAxis2 = 58; | |
DRGenOffsetsAxis3 = 84; | |
DRGenOffsetsAxis4 = 110; | |
DRGenOffsetsAxis5 = 136; | |
DRGenOffsetsAxis6 = 162; | |
DRGenOffsetsAxis7 = 188; | |
DRGenOffsetsAxis8 = 214; | |
DRGenOffsetsEnd = 240; | |
{' ** The following constants are OBSOLETE ** | |
' General offsets for firmware with coordinated motion T axis - data record revsion 3} | |
wTDRGenOffsetsSampleNumber = 0; | |
wTDRGenOffsetsGeneralInput0 = 2; | |
wTDRGenOffsetsGeneralInput1 = 3; | |
wTDRGenOffsetsGeneralInput2 = 4; | |
wTDRGenOffsetsGeneralInput3 = 5; | |
wTDRGenOffsetsGeneralInput4 = 6; | |
wTDRGenOffsetsGeneralInput5 = 7; | |
wTDRGenOffsetsGeneralInput6 = 8; | |
wTDRGenOffsetsGeneralInput7 = 9; | |
wTDRGenOffsetsGeneralInput8 = 10; | |
wTDRGenOffsetsGeneralInput9 = 11; | |
wTDRGenOffsetsGeneralOutput0 = 12; | |
wTDRGenOffsetsGeneralOutput1 = 13; | |
wTDRGenOffsetsGeneralOutput2 = 14; | |
wTDRGenOffsetsGeneralOutput3 = 15; | |
wTDRGenOffsetsGeneralOutput4 = 16; | |
wTDRGenOffsetsGeneralOutput5 = 17; | |
wTDRGenOffsetsGeneralOutput6 = 18; | |
wTDRGenOffsetsGeneralOutput7 = 19; | |
wTDRGenOffsetsGeneralOutput8 = 20; | |
wTDRGenOffsetsGeneralOutput9 = 21; | |
wTDRGenOffsetsErrorCode = 22; | |
wTDRGenOffsetsGeneralStatus = 23; | |
wTDRGenOffsetsSegmentCountS = 24; | |
wTDRGenOffsetsCoordinatedMoveStatusS = 26; | |
wTDRGenOffsetsCoordinatedMoveDistanceS = 28; | |
wTDRGenOffsetsSegmentCountT = 32; | |
wTDRGenOffsetsCoordinatedMoveStatusT = 34; | |
wTDRGenOffsetsCoordinatedMoveDistanceT = 36; | |
wTDRGenOffsetsAxis1 = 40; | |
wTDRGenOffsetsAxis2 = 66; | |
wTDRGenOffsetsAxis3 = 92; | |
wTDRGenOffsetsAxis4 = 118; | |
wTDRGenOffsetsAxis5 = 144; | |
wTDRGenOffsetsAxis6 = 170; | |
wTDRGenOffsetsAxis7 = 196; | |
wTDRGenOffsetsAxis8 = 222; | |
wTDRGenOffsetsEnd = 248; | |
{' Constant values for data record axis data item offsets | |
' IMPORTANT - Values can change between revisions} | |
DRAxisOffsetsNoAxis = 0; | |
DRAxisOffsetsAxisStatus = 0; | |
DRAxisOffsetsAxisSwitches = 2; | |
DRAxisOffsetsAxisStopCode = 3; | |
DRAxisOffsetsAxisReferencePosition = 4; | |
DRAxisOffsetsAxisMotorPosition = 8; | |
DRAxisOffsetsAxisPositionError = 12; | |
DRAxisOffsetsAxisAuxillaryPosition = 16; | |
DRAxisOffsetsAxisVelocity = 20; | |
DRAxisOffsetsAxisTorque = 24; | |
DRAxisOffsetsEnd = 26; | |
//' Constant values for GALILREGISTRY structure | |
//' Controller Type | |
ControllerTypeISABus = 0; | |
ControllerTypeSerial = 1; | |
ControllerTypePCIBus = 2; | |
ControllerTypeUSB = 3; | |
//' Device Drivers | |
DeviceDriverWinRT = 0; | |
DeviceDriverGalil = 1; | |
//' Serial Handshake | |
SerialHandshakeHardware = 0; | |
SerialHandshakeSoftware = 1; | |
//' Data Record Access | |
DataRecordAccessNone = 0 ; | |
DataRecordAccessDMA = 1; | |
DataRecordAccessFIFO = 2 ; | |
//' Ethernet Protocol | |
EthernetProtocolTCP = 0; | |
EthernetProtocolUDP = 1; | |
//' Structures | |
//' To add/change/delete registry information | |
type | |
GALILREGISTRY = record | |
Model: array[0..15]of Char; | |
DeviceNumber, | |
DeviceDriver, | |
Timeout, | |
Delay, | |
ControllerType, | |
CommPort, | |
CommSpeed, | |
Handshake, | |
Address, | |
iinterrupt, | |
DataRecordAccess, | |
DMAChannel, | |
DataRecordSize, | |
RefreshRate, | |
SerialNumber: integer; | |
PNPHardwareKey: array[0..63] of Char; | |
end; | |
// Function prototypes | |
TDMCOpen = function(Controller, hWnd: integer; var phDmc: integer): integer; stdcall; | |
{' Open communications with the Galil controller. | |
' Controller A number between 1 and 16. Up to 16 Galil controllers may be | |
' addressed per process. | |
' hWnd The window handle to use for notifying the application | |
' program of an interrupt. | |
' phDmc Handle to the Galil controller to be use for all subsequent | |
' API calls.} | |
TDMCOpen2 = function(Controller, ThreadID: integer; var phDmc: integer): integer; stdcall; | |
{' Open communications with the Galil controller. | |
' Controller A number between 1 and 16. Up to 16 Galil controllers may be | |
' addressed per process. | |
' ThreadID The thread id to use for notifying the application | |
' program of an interrupt. | |
' phDmc Handle to the Galil controller to be use for all subsequent | |
' API calls.} | |
TDMCGetHandle = function(Controller: integer; var phDmc: integer): integer; stdcall; | |
{' Get the handle associated with a particular Galil controller. | |
' Controller A number between 1 and 16. Up to 16 Galil controllers may be | |
' addressed per process. | |
' phDmc Handle to the Galil controller to be use for all subsequent | |
' API calls.} | |
TDMCClose = function(hDmc: integer): integer; stdcall; | |
{' Close communications with the Galil controller. | |
' hDmc Handle to the Galil controller. } | |
TDMCCommand = function(hDmc : integer; CommandString, Response: PChar; ResponseLength: integer): integer; stdcall; | |
{' Send a command to the Galil controller. | |
' NOTE: This function can only send commands or groups of commands up to | |
' 1024 bytes long. | |
' hDmc Handle to the Galil controller. | |
' CommandString The command to send to the Galil controller. | |
' Response Buffer to receive the response data. | |
' ResponseLength Length of the buffer.} | |
TDMCFastCommand = function(hDmc: integer; CommandString: PChar): integer; stdcall; | |
{' Send a command to the Galil controller without the overhead of waiting for a response. Use this function with | |
' caution as command errors will not be reported and the out-going FIFO or communciations buffer | |
' may fill up. This function is intended to be used in routines which provide data records for the Galil | |
' DL and QD commands which do not return a response. Other uses may be to send contour data. | |
' NOTE: This function can only send commands or groups of commands up to | |
' 1024 bytes long. | |
' hDmc Handle to the Galil controller. | |
' CommandString The command to send to the Galil controller.} | |
TDMCGetUnsolicitedResponse = function(hDmc: integer; Response: PChar; ResponseLength: integer): integer; stdcall; | |
{' Query the Galil controller for unsolicited responses. These are messages | |
' output from programs running in the background in the Galil controller. | |
' hDmc Handle to the Galil controller. | |
' Response Buffer to receive the response data. | |
' ResponseLength Length of the buffer. | |
} | |
TDMCWriteData = function(hDmc: integer; Buffer: PChar; BufferLength: integer; var BytesWritten: integer): integer; stdcall; | |
{' Low-level I/O routine to write data to the Galil controller. Data is written | |
' to the Galil controller only if it is "ready" to receive it. The function | |
' will attempt to write exactly cbBuffer characters to the controller. | |
' NOTE: For Win32 and WinRT driver the maximum number of bytes which can be written | |
' each time is 64. There are no restrictions with the Galil driver. | |
' hDmc Handle to the Galil controller. | |
' Buffer Buffer to write the data from. Data does not need to be | |
' NULL terminated. | |
' BufferLength Length of the data in the buffer. | |
' BytesWritten Number of bytes written. | |
} | |
TDMCReadData = function(hDmc: integer; Buffer: PChar; BufferLength: integer; var BytesRead: integer): integer; stdcall; | |
{' Low-level I/O routine to read data from the Galil controller. The routine | |
' will read what ever is currently in the FIFO (bus controller) or | |
' communications port input queue (serial controller). The function will read | |
' up to cbBuffer characters from the controller. The data placed in the user | |
' buffer (pchBuffer) is NOT NULL terminated. The data returned is not guaranteed | |
' to be a complete response - you may have to call this function repeatedly to | |
' get a complete response. | |
' NOTE: For Win32 and WinRT driver the maximum number of bytes which can be read | |
' each time is 64. There are no restrictions with the Galil driver. | |
' hDmc Handle to the Galil controller. | |
' Buffer Buffer to read the data into. Data will not be NULL | |
' terminated. | |
' BufferLength Length of the buffer. | |
' BytesRead Number of bytes read.} | |
TDMCGetAdditionalResponseLen = function(hDmc: integer; var ResponseLength: integer): integer; stdcall; | |
{' Query the Galil controller for the length of the additional response data. There will be more | |
' response data available if DMCCommand returned DMCERROR_BUFFERFULL. | |
' hDmc Handle to the Galil controller. | |
' ResponseLength Length of the additional response data. | |
} | |
TDMCGetAdditionalResponse = function(hDmc: integer; Response: PChar; ResponseLength: integer): integer; stdcall; | |
{' Query the Galil controller for more response data. There will be more | |
' response data available if DMCCommand returned DMCERROR_BUFFERFULL. | |
' hDmc Handle to the Galil controller. | |
' Response Buffer to receive the response data. | |
' ResponseLength Length of the buffer. | |
} | |
TDMCError = function(hDmc: integer; var ErrorCode: integer; var sMessage: WideChar; var MessageLength: integer): integer; stdcall; | |
{' Retrieve the error message text from a DMCERROR_COMMAND error. | |
' hDmc Handle to the Galil controller. | |
' ErrorCode Error returned from API function. | |
' Message Buffer to receive the error message text. | |
' MessageLength Length of the buffer. | |
} | |
TDMCClear = function(hDmc: integer): integer; stdcall; | |
{' Clear the Galil controller FIFO. | |
' hDmc Handle to the Galil controller.} | |
TDMCReset = function(hDmc: integer): integer; stdcall; | |
{' Reset the Galil controller. | |
' hDmc Handle to the Galil controller. | |
} | |
TDMCMasterReset = function(hDmc: integer): integer; stdcall; | |
{' Master reset the Galil controller. | |
' hDmc Handle to the Galil controller. | |
} | |
TDMCVersion = function(hDmc: integer; Version : PChar; VersionLength: integer): integer; stdcall; | |
{' Get the version of the Galil controller. | |
' hDmc Handle to the Galil controller. | |
' Version Buffer to receive the version information. | |
' VersionLength Length of the buffer. | |
} | |
TDMCDownloadFile = function(hDmc: integer; FileName, sLabel: PChar): integer; stdcall; | |
{' Download a file to the Galil controller. | |
' hDmc Handle to the Galil controller. | |
' FileName File name to download to the Galil controller. | |
' Label Program label to download to. This argument is ignored if | |
' NULL. | |
} | |
{ | |
Public Declare Function DMCDownloadFromBuffer = function ( hDmc As Long, Buffer : PChar;, Label : PChar;) As Long | |
' Download a file to the Galil controller. | |
' hDmc Handle to the Galil controller. | |
' Buffer Buffer of DMC commands to download to the Galil controller. | |
' Label Program label to download to. This argument is ignored if | |
' NULL. | |
Public Declare Function DMCUploadFile = function ( hDmc As Long, FileName : PChar;) As Long | |
' Upload a file from the Galil controller. | |
' FileName File name to upload from the Galil controller. | |
Public Declare Function DMCUploadToBuffer = function ( hDmc As Long, Buffer : PChar;, BufferLength As Long) As Long | |
' Upload a file from the Galil controller. | |
' Buffer Buffer of DMC commands to upload from the Galil controller. | |
' BufferLength Length of the buffer. | |
Public Declare Function DMCSendFile = function ( hDmc As Long, FileName : PChar;) As Long | |
' Send a file to the Galil controller. | |
' hDmc Handle to the Galil controller. | |
' FileName File name to send to the Galil controller. | |
Public Declare Function DMCArrayDownload = function ( hDmc As Long, ArrayName : PChar;, FirstElement : integer; , LastElement : integer; , Data : PChar;, DataLength As Long, BytesWritten As Long) As Long | |
' Download an array to the Galil controller. The array must exist. Array data can be | |
' delimited by a comma or CR (0x0D) or CR/LF (0x0D0A). | |
' NOTE: The firmware on the controller must be recent enough to support the QD command. | |
' hDmc Handle to the Galil controller. | |
' ArrayName Array name to download to the Galil controller. | |
' FirstElement First array element. | |
' LastElement Last array element. | |
' Data Buffer to write the array data from. Data does not need to be | |
' NULL terminated. | |
' DataLength Length of the array data in the buffer. | |
' BytesWritten Number of bytes written. | |
Public Declare Function DMCArrayUpload = function ( hDmc : integer;, ArrayName : PChar;, FirstElement : integer; , LastElement : integer; , Buffer : PChar;, BufferLength : integer;, BytesRead : integer;, Comma : integer; ) : integer; | |
' Upload an array from the Galil controller. The array must exist. Array data will be | |
' delimited by a comma or CR (0x0D) depending of the value of fComma. | |
' NOTE: The firmware on the controller must be recent enough to support the QU command. | |
' hDmc Handle to the Galil controller. | |
' ArrayName Array name to upload from the Galil controller. | |
' FirstElement First array element. | |
' LastElement Last array element. | |
' Buffer Buffer to read the array data into. Array data will not be | |
' NULL terminated. | |
' BufferLength Length of the buffer. | |
' BytesRead Number of bytes read. | |
} | |
TDMCRefreshDataRecord = function ( hDmc : integer; Length : integer) : integer; stdcall; | |
{' Refresh the data record used for fast polling. | |
' hDmc Handle to the Galil controller. | |
' Length Refresh size in bytes. Set to 0 unless you do not want a full-buffer | |
' refresh. } | |
TDMCGetDataRecord = function ( hDmc : integer; GeneralOffset : integer; AxisInfoOffset : integer; DataType : integer; Data : integer) : integer; stdcall; | |
{' Get a data item from the data record used for fast polling. Gets one item from the | |
' data record by using offsets. To retrieve data record items by Id instead of offset, | |
' use the function DMCGetDataRecordByItemId. | |
' hDmc Handle to the Galil controller. | |
' GeneralOffset Data record offset for general data item. | |
' AxisInfoOffset Additional data record offset for axis data item. | |
' DataType Data type of the data item. If you are using the standard, | |
' pre-defined offsets, set this argument to zero before calling this | |
' function. The actual data type of the data item is returned on output. | |
' Data Buffer to receive the data record data. Output only.} | |
TDMCGetDataRecordByItemId = function (hDmc, ItemId, AxisId, DataType, Data : integer) : integer; stdcall; | |
{' Get a data item from the data record used for fast polling. Gets one item from the | |
' data record by using Id. To retrieve data record items by offset instead of Id, | |
' use the function DMCGetDataRecord. | |
' hDmc Handle to the Galil controller. | |
' ItemId Data record item Id. | |
' AxisId Axis Id used for axis data items. | |
' DataType Data type of the data item. The data type of the | |
' data item is returned on output. Output Only. | |
' Data Buffer to receive the data record data. Output only.} | |
TDMCGetDataRecordRevision = function (hDmc, Revision : integer) : integer; stdcall; | |
{' Get the revision of the data record structure used for fast polling. | |
' hDmc Handle to the Galil controller. | |
' Revision The revision of the data record structure is returned on | |
' output. Output Only.} | |
{ TDMCDiagnosticsOn = function ( hDmc : integer;, FileName : PChar;, AppendFile : integer; ) : integer; | |
' Turn on diagnostics. | |
' hDmc Handle to the Galil controller. | |
' FileName File name for the diagnostic file. | |
' AppendFile True if the file will open for append, otherwise False. | |
TDMCDiagnosticsOff = function ( hDmc : integer;) : integer; | |
' Turn off diagnostics. | |
' hDmc Handle to the Galil controller. } | |
TDMCGetTimeout = function (hDmc : integer; Timeout : integer) : integer; stdcall; | |
{ Get current timeout value. | |
' hDmc Handle to the Galil controller. | |
' Timeout Current timeout value in milliseconds. | |
} | |
TDMCSetTimeout = function (hDmc : integer; Timeout : integer) : integer; stdcall; | |
{Set timeout value. | |
' hDmc Handle to the Galil controller. | |
' Timeout Timeout value in milliseconds. | |
} | |
{TDMCGetDelay = function ( hDmc : integer;, Delay : integer;) : integer; | |
' Get current delay value. | |
' *** THIS FUNCTION IS OBSOLETE. DELAY IS NO LONGER USED *** | |
' hDmc Handle to the Galil controller. | |
' Delay Current delay value. | |
TDMCSetDelay = function ( hDmc : integer;, Delay : integer;) : integer; | |
' Set delay value. | |
' *** THIS FUNCTION IS OBSOLETE. DELAY IS NO LONGER USED *** | |
' hDmc Handle to the Galil controller. | |
' Delay Delay value. | |
} | |
TDMCBinaryCommand = function (hDmc : integer; Command : PChar; CommandLength : integer; Response : PChar; ResponseLength : integer) : integer; stdcall; | |
{' Send a DMC command in binary format to the Galil controller. | |
' hDmc Handle to the Galil controller. | |
' Command The command to send to the Galil controller. | |
' CommandLength The length of the command (binary commands are not null-terminated). | |
' Response Buffer to receive the response data. If the buffer is too | |
' small to recieve all the response data from the controller, | |
' the error code DMCERROR_BUFFERFULL will be returned. The | |
' user may get additional response data by calling the | |
' function DMCGetAdditionalResponse. The length of the | |
' additonal response data may ascertained by call the | |
' function DMCGetAdditionalResponseLen. If the response | |
' data from the controller is too large for the internal | |
' additional response buffer, the error code | |
' DMCERROR_RESPONSEDATA will be returned. Output only. | |
' ResponseLength Length of the buffer. | |
} | |
{ TDMCSendBinaryFile = function ( hDmc : integer;, FileName : PChar;) : integer; | |
' Send a file consisting of DMC commands in binary format to the Galil controller. | |
' hDmc Handle to the Galil controller. | |
' FileName File name to send to the Galil controller. | |
TDMCCommand_BinaryToAscii = function ( hDmc : integer;, BinCommand : PChar;, BinCommandLength : integer;, AscResult : PChar;, AscResultLength : integer;, AscResultReturnedLength : integer;) : integer; | |
' Convert a binary DMC command to an ascii DMC command. | |
' hDmc Handle to the Galil controller. | |
' BinCommand Binary DMC command(s) to be converted. | |
' BinCommandLength Length of DMC command(s). | |
' AscResult Buffer to receive the translated DMC command. | |
' AscResultLength Length of the buffer. | |
' AscResultReturnedLength Length of the translated DMC command. | |
TDMCCommand_AsciiToBinary = function ( hDmc : integer;, AscCommand : PChar;, AscCommandLength : integer;, BinResult : PChar;, BinaryResult : integer;, BinResultReturnedLength : integer;) : integer; | |
' Convert an ascii DMC command to a binary DMC command. | |
' hDmc Handle to the Galil controller. | |
' AscCommand Ascii DMC command(s) to be converted. | |
' AscCommandLength Length of DMC command(s). | |
' BinResult Buffer to receive the translated DMC command. | |
' BinResultLength Length of the buffer. | |
' BinResultReturnedLength Length of the translated DMC command. | |
TDMCFile_AsciiToBinary = function ( hDmc : integer;, InputFileName : PChar;, OutputFileName : PChar;) : integer; | |
' Convert a file consisting of ascii commands to a file consisting of binary commands. | |
' hDmc Handle to the Galil controller. | |
' InputFileName File name for the input ascii file. | |
' OutputFileName File name for the output binary file. | |
TDMCFile_BinaryToAscii = function ( hDmc : integer;, InputFileName : PChar;, OutputFileName : PChar;) : integer; | |
' Convert a file consisting of binary commands to a file consisting of ascii commands. | |
' hDmc Handle to the Galil controller. | |
' InputFileName File name for the input binary file. | |
' OutputFileName File name for the output ascii file. | |
TDMCReadSpecialConversionFile = function ( hDmc : integer;, FileName : PChar;) : integer; | |
' Read into memory a special BinaryToAscii/AsciiToBinary conversion table. | |
' hDmc Handle to the Galil controller. | |
' FileName File name for the special conversion file. | |
TDMCAddGalilRegistry = function (GALILREGISTRY As GALILREGISTRY, Controller : integer; ) : integer; | |
' Add a Galil controller to the Windows registry. | |
' galilregistry Pointer to a GALILREGISTRY struct. | |
' Controller Galil controller number assigned by the successful completion of this function. | |
TDMCModifyGalilRegistry = function ( Controller : integer; , GALILREGISTRY As GALILREGISTRY) : integer; | |
' Change a Galil controller in the Windows registry. | |
' Controller Galil controller number. | |
' galilregistry Pointer to a GALILREGISTRY struct. | |
TDMCDeleteGalilRegistry = function ( Controller : integer; ) : integer; | |
' Delete a Galil controller in the Windows registry. | |
' Controller Galil controller number. Use -1 to delete all Galil controllers. | |
TDMCGetGalilRegistryInfo = function ( Controller : integer; , GALILREGISTRY As GALILREGISTRY) : integer; | |
' Get Windows registry information for a given Galil controller. | |
' Controller Galil controller number. | |
' galilregistry Pointer to a GALILREGISTRY struct. | |
TDMCRegisterPnpControllers = function (Count : integer; ) : integer; | |
' Update Windows registry for all Galil Plug-and-Play (PnP) controllers. This function | |
' will add new controllers to the registry or update existing ones. | |
' Count Pointer to the number of Galil PnP controllers registered (and/or updated). | |
TDMCSelectController = function ( hWnd : integer;) : integer; | |
' Select a Galil motion controller from a list of registered controllers. Returns the | |
' selected controller number or -1 if no controller was selected. | |
' NOTE: This function invokes a dialog window. | |
' hwnd The window handle of the calling application. If NULL, the | |
' window with the current input focus is used. | |
Public Declare Sub DMCEditRegistry = function ( hWnd : integer; ) | |
' Edit the Windows registry: add, change, or delete Galil motion controllers. | |
' NOTE: This function invokes a dialog window. | |
' hwnd The window handle of the calling application. If NULL, the | |
' window with the current input focus is used. | |
} | |
TDMCWaitForMotionComplete = function (hDmc : integer; Axes : PChar; DispatchMsgs : WordBool) : integer; stdcall; | |
{' Wait for motion complete by creating a thread to query the controller. The function returns | |
' when motion is complete. | |
' hDmc Handle to the Galil controller. | |
' Axes Which axes to wait for: X, Y, Z, W, E, F, G, H, or S for | |
' coordinated motion. To wait for more than one axis (other than | |
' coordinated motion), simply concatenate the axis letters in the string. | |
' DispatchMsgs Set to TRUE if you want to get and dispatch Windows messages | |
' while waiting for motion complete. This flag is always TRUE for Win16. | |
} | |
{ TDMCDownloadFirmwareFile = function ( hDmc : integer;, FileName : PChar;, DisplayDialog : integer; ) : integer; | |
' Update the controller's firmware. This function will open a binary firmware file and refresh | |
' the flash EEPROM of the controller. | |
' hDmc Handle to the Galil controller. | |
' FileName File name to download to the Galil controller. | |
' DisplayDialog Display a progress dialog to the user. | |
TDMCReadRegister = function ( hDmc : integer;, Offset : integer; , Status As Byte) : integer; | |
' Read from a register (FIFO) of a bus controller. | |
' NOTE: This function is for Galil bus controllers and Win32 only. | |
' ** THIS FUNCTION IS FOR EXPERIENCED PROGRAMMERS ONLY ** | |
' hDmc Handle to the Galil controller. | |
' Offset Register offset. 0 = mailbox, 1 = status. | |
' Status Buffer to receive status register data. | |
TDMCWriteRegister = function ( hDmc : integer;, Offset : integer; , Status As Byte) : integer; | |
' Write to a register (FIFO) of a bus controller. | |
' NOTE: This function is for Galil bus controllers and Win32 only. | |
' ** THIS FUNCTION IS FOR EXPERIENCED PROGRAMMERS ONLY ** | |
' hDmc Handle to the Galil controller. | |
' Offset Register offset. 0 = mailbox, 1 = status. | |
' Status Status register data. | |
} | |
implementation | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit fileinfou; | |
interface | |
uses Windows, SysUtils, Classes, Graphics, Forms, Controls, StdCtrls, | |
Buttons, ExtCtrls, ComCtrls, Spin, Mainfrm; | |
type | |
TConfigdlg = class(TForm) | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
PageControl1: TPageControl; | |
TabSheet1: TTabSheet; | |
TabSheet2: TTabSheet; | |
TabSheet3: TTabSheet; | |
TabSheet4: TTabSheet; | |
TabSheet5: TTabSheet; | |
CheckBox1: TCheckBox; | |
Label2: TLabel; | |
ComboBox2: TComboBox; | |
Label3: TLabel; | |
Edit1: TEdit; | |
Label4: TLabel; | |
Label5: TLabel; | |
Label6: TLabel; | |
Label7: TLabel; | |
Label8: TLabel; | |
SpinEdit1: TSpinEdit; | |
SpinEdit2: TSpinEdit; | |
SpinEdit3: TSpinEdit; | |
SpinEdit4: TSpinEdit; | |
Label13: TLabel; | |
Label14: TLabel; | |
Label15: TLabel; | |
Label16: TLabel; | |
Label17: TLabel; | |
Label1: TLabel; | |
Label20: TLabel; | |
CheckBox2: TCheckBox; | |
Label21: TLabel; | |
Edit2: TEdit; | |
Label22: TLabel; | |
ComboBox1: TComboBox; | |
CheckBox3: TCheckBox; | |
Edit3: TEdit; | |
Label23: TLabel; | |
Label24: TLabel; | |
ComboBox3: TComboBox; | |
Button1: TButton; | |
Label10: TLabel; | |
Label11: TLabel; | |
Label12: TLabel; | |
Label25: TLabel; | |
Label26: TLabel; | |
ComboBox4: TComboBox; | |
Edit4: TEdit; | |
Edit5: TEdit; | |
Label27: TLabel; | |
SpinEdit6: TSpinEdit; | |
Label28: TLabel; | |
Bevel2: TBevel; | |
Label29: TLabel; | |
SpinButton1: TSpinButton; | |
SpeedButton1: TSpeedButton; | |
Edit9: TEdit; | |
Edit10: TEdit; | |
Label9: TLabel; | |
CheckBox4: TCheckBox; | |
Label18: TLabel; | |
Edit6: TEdit; | |
Label19: TLabel; | |
ComboBox5: TComboBox; | |
Label30: TLabel; | |
Edit7: TEdit; | |
Label31: TLabel; | |
ComboBox6: TComboBox; | |
Label32: TLabel; | |
Edit8: TEdit; | |
Label33: TLabel; | |
Label34: TLabel; | |
Edit11: TEdit; | |
Label35: TLabel; | |
SpinEdit5: TSpinEdit; | |
Label36: TLabel; | |
Bevel1: TBevel; | |
Label37: TLabel; | |
Label38: TLabel; | |
Label39: TLabel; | |
Label41: TLabel; | |
Label42: TLabel; | |
Label43: TLabel; | |
Label44: TLabel; | |
Label45: TLabel; | |
Label40: TLabel; | |
Label46: TLabel; | |
Bevel3: TBevel; | |
SpinButton2: TSpinButton; | |
Label47: TLabel; | |
Bevel4: TBevel; | |
Label48: TLabel; | |
Bevel5: TBevel; | |
Label49: TLabel; | |
Bevel6: TBevel; | |
Label50: TLabel; | |
procedure FormShow(Sender: TObject); | |
procedure FormCreate(Sender: TObject); | |
procedure Edit7Change(Sender: TObject); | |
procedure Edit5Change(Sender: TObject); | |
procedure CheckBox1Click(Sender: TObject); | |
procedure CheckBox2Click(Sender: TObject); | |
procedure CheckBox3Click(Sender: TObject); | |
procedure CheckBox4Click(Sender: TObject); | |
procedure SpeedButton1Click(Sender: TObject); | |
procedure Button1Click(Sender: TObject); | |
procedure BitBtn1Click(Sender: TObject); | |
procedure SpinEdit1Change(Sender: TObject); | |
procedure SpinEdit2Change(Sender: TObject); | |
procedure SpinEdit3Change(Sender: TObject); | |
procedure SpinEdit4Change(Sender: TObject); | |
procedure Edit9Change(Sender: TObject); | |
procedure Edit1Change(Sender: TObject); | |
procedure ComboBox2Change(Sender: TObject); | |
procedure Edit2Change(Sender: TObject); | |
procedure ComboBox1Change(Sender: TObject); | |
procedure Edit3Change(Sender: TObject); | |
procedure ComboBox3Change(Sender: TObject); | |
procedure Edit10Change(Sender: TObject); | |
procedure Edit4Change(Sender: TObject); | |
procedure SpinEdit6Change(Sender: TObject); | |
procedure Edit6Change(Sender: TObject); | |
procedure ComboBox5Change(Sender: TObject); | |
procedure Edit8Change(Sender: TObject); | |
procedure Edit11Change(Sender: TObject); | |
procedure SpinEdit5Change(Sender: TObject); | |
procedure SpinButton1DownClick(Sender: TObject); | |
procedure SpinButton1UpClick(Sender: TObject); | |
procedure SpinButton2DownClick(Sender: TObject); | |
procedure SpinButton2UpClick(Sender: TObject); | |
private | |
{ Private declarations } | |
{Modification flags} | |
bModified, | |
bBlockEdit9Change, | |
bFrameWidthChanged, | |
bFrameHeightChanged, | |
bFrameXOffsetChanged, | |
bFrameYOffsetChanged, | |
bFrameRateChanged, | |
bCh1Changed, | |
bCh2Changed, | |
bCh3Changed, | |
bCh3DataPtsChanged, | |
bCh4Changed, | |
bCh4DataPtsChanged: boolean; | |
newPixelRate: integer; | |
newFrameRate: double; | |
procedure EnableCh1; | |
procedure EnableCh2; | |
procedure EnableCh3; | |
procedure EnableCh4; | |
procedure OnPixelRateChanged; | |
procedure SetConvFactorUnit1; | |
procedure SetConvFactorUnit2; | |
function ValidateFrameWidth(value: integer): boolean; | |
function ValidateFrameHeight(var value: integer): boolean; | |
function ValidateXOffset(value: integer): boolean; | |
function ValidateYOffset(value: integer): boolean; | |
function ValidateFrameRate(value: double): boolean; | |
function ValidateVideoChs: boolean; | |
function ValidateDataPtsCh(value: integer): boolean; | |
public | |
{ Public declarations } | |
bNoFrameDimChange: boolean; | |
end; | |
var | |
Configdlg: TConfigdlg; | |
implementation | |
{$R *.DFM} | |
uses MPUnit, Dialogs, Math; | |
procedure TConfigdlg.EnableCh1; | |
begin | |
Edit1.Enabled := CheckBox1.Checked; | |
ComboBox2.Enabled := CheckBox1.Checked; | |
end; | |
procedure TConfigdlg.EnableCh2; | |
begin | |
Edit2.Enabled := CheckBox2.Checked; | |
ComboBox1.Enabled := CheckBox2.Checked; | |
end; | |
procedure TConfigdlg.EnableCh3; | |
begin | |
Edit3.Enabled := CheckBox3.Checked; | |
ComboBox3.Enabled := CheckBox3.Checked; | |
Edit5.Enabled := CheckBox3.Checked; | |
ComboBox4.Enabled := CheckBox3.Checked; | |
Edit10.Enabled := CheckBox3.Checked; | |
Edit4.Enabled := CheckBox3.Checked; | |
SpinEdit6.Enabled := CheckBox3.Checked; | |
Label27.Enabled := CheckBox3.Checked; | |
Label28.Enabled := CheckBox3.Checked; | |
Label45.Enabled := CheckBox3.Checked; | |
end; | |
procedure TConfigdlg.EnableCh4; | |
begin | |
Edit6.Enabled := CheckBox4.Checked; | |
ComboBox5.Enabled := CheckBox4.Checked; | |
Edit7.Enabled := CheckBox4.Checked; | |
ComboBox6.Enabled := CheckBox4.Checked; | |
Edit8.Enabled := CheckBox4.Checked; | |
Edit11.Enabled := CheckBox4.Checked; | |
SpinEdit5.Enabled := CheckBox4.Checked; | |
Label33.Enabled := CheckBox4.Checked; | |
Label37.Enabled := CheckBox4.Checked; | |
Label44.Enabled := CheckBox3.Checked; | |
end; | |
procedure TConfigdlg.OnPixelRateChanged; | |
begin | |
Label46.Caption := IntToStr(newPixelRate * 50) + ' ns'; | |
Label48.Caption := Format('%4.2f', [1e3/(newPixelRate * 50)]) + ' MHz'; | |
Label28.Caption := Format('%5f', [newFrameRate * SpinEdit6.Value]); | |
Label37.Caption := Format('%5f', [newFrameRate * SpinEdit5.Value]); | |
end; | |
procedure TConfigdlg.SetConvFactorUnit1; | |
begin | |
Label27.Caption := ComboBox4.Items[ComboBox4.ItemIndex] + Edit5.Text + '/ V at input'; | |
Label45.Caption := ComboBox4.Items[ComboBox4.ItemIndex] + Edit5.Text; | |
end; | |
procedure TConfigdlg.SetConvFactorUnit2; | |
begin | |
Label33.Caption := ComboBox6.Items[ComboBox6.ItemIndex] + Edit7.Text + '/ V at input'; | |
Label44.Caption := ComboBox6.Items[ComboBox6.ItemIndex] + Edit7.Text; | |
end; | |
function TConfigdlg.ValidateFrameWidth(value: integer): boolean; | |
begin | |
Result := (value >= 10) and (value <= 500); | |
end; | |
function TConfigdlg.ValidateFrameHeight(var value: integer): boolean; | |
begin | |
Result := (value >= 10) and (value <= 500); | |
if Result and Odd(value) then | |
begin | |
MessageDlg('Frame height will be adjusted to be a multiple of 2 lines.', | |
mtInformation, [mbOK], 0); | |
value := 2 * (value div 2); | |
if value < 10 then value := 10; | |
end; | |
end; | |
function TConfigdlg.ValidateXOffset(value: integer): boolean; | |
begin | |
Result := (value >= 0) and (value <= 490); | |
end; | |
function TConfigdlg.ValidateYOffset(value: integer): boolean; | |
begin | |
Result := (value >= 0) and (value <= 490); | |
end; | |
function TConfigdlg.ValidateFrameRate(value: double): boolean; | |
var valFrameRate: double; | |
valPixelRate: integer; | |
begin | |
Mainform.Configuration.GetMaxFrameRate(SpinEdit1.Value, SpinEdit2.Value, valFrameRate, valPixelRate); | |
Result := (value > 0) and (value <= valFrameRate); | |
end; | |
function TConfigdlg.ValidateVideoChs: boolean; | |
begin | |
Result := Checkbox1.Checked or Checkbox2.Checked; | |
end; | |
function TConfigdlg.ValidateDataPtsCh(value: integer): boolean; | |
begin | |
Result := (value >= 0) and (value <= spinEdit1.Value * spinEdit2.Value); | |
end; | |
procedure TConfigdlg.FormShow(Sender: TObject); | |
begin | |
bModified := False; | |
with mainform.Configuration do | |
begin | |
Label50.Caption := ScanModeToString(ScanMode); | |
if not bNoFrameDimChange then | |
begin | |
SpinEdit1.Value := FrameWidth; | |
SpinEdit2.Value := FrameHeight; | |
SpinEdit3.Value := XFrameOffset; | |
SpinEdit4.Value := YFrameOffset; | |
newFrameRate := FrameRate; | |
newPixelRate := PixelClock; | |
end | |
else | |
begin | |
bModified := True; {main form has modified it} | |
GetMaxFrameRate(SpinEdit1.Value, SpinEdit2.Value, newFrameRate, newPixelRate); | |
end; | |
bBlockEdit9Change := True; | |
Edit9.Text := Format('%f', [newFrameRate]); | |
bBlockEdit9Change := False; | |
OnPixelRateChanged; | |
CheckBox1.Checked := ChEnabled[0]; | |
Edit1.Text := ChNames[0]; | |
ComboBox2.ItemIndex := Integer(ChInputRanges[0]); | |
CheckBox2.Checked := ChEnabled[1]; | |
Edit2.Text := ChNames[1]; | |
ComboBox1.ItemIndex := Integer(ChInputRanges[1]); | |
CheckBox3.Checked := ChEnabled[2]; | |
Edit3.Text := ChNames[2]; | |
ComboBox3.ItemIndex := Integer(ChInputRanges[2]); | |
Edit5.Text := ChUnits[2]; | |
ComboBox4.ItemIndex := Integer(ChPrefixes[2]); | |
Edit4.Text := Format('%g', [ChOffsets[2]]); | |
SpinEdit6.Value := ChDataPtsPerFrames[2]; | |
Label28.Caption := Format('%f', [ChAnalogFreqs[2]]); | |
SetConvFactorUnit1; | |
CheckBox4.Checked := ChEnabled[3]; | |
Edit6.Text := ChNames[3]; | |
ComboBox5.ItemIndex := Integer(ChInputRanges[3]); | |
Edit7.Text := ChUnits[3]; | |
ComboBox6.ItemIndex := Integer(ChPrefixes[3]); | |
Edit11.Text := Format('%g', [ChOffsets[3]]); | |
SpinEdit5.Value := ChDataPtsPerFrames[3]; | |
Label37.Caption := Format('%f', [ChAnalogFreqs[2]]); | |
SetConvFactorUnit2; | |
EnableCh1; | |
EnableCh2; | |
EnableCh3; | |
EnableCh4; | |
end; | |
bFrameWidthChanged := False; | |
bFrameHeightChanged := False; | |
bFrameXOffsetChanged := False; | |
bFrameYOffsetChanged := False; | |
bFrameRateChanged := False; | |
bCh1Changed := False; | |
bCh2Changed := False; | |
bCh3Changed := False; | |
bCh3DataPtsChanged := False; | |
bCh4Changed := False; | |
bCh4DataPtsChanged := False; | |
end; | |
procedure TConfigdlg.FormCreate(Sender: TObject); | |
begin | |
FillInputRangeListBox(ComboBox2); | |
FillInputRangeListBox(ComboBox1); | |
FillInputRangeListBox(ComboBox3); | |
FillInputRangeListBox(ComboBox5); | |
FillUnitListBox(ComboBox4, ''); | |
FillUnitListBox(ComboBox6, ''); | |
end; | |
procedure TConfigdlg.Edit7Change(Sender: TObject); | |
begin | |
SetConvFactorUnit2; | |
bModified := True; | |
end; | |
procedure TConfigdlg.Edit5Change(Sender: TObject); | |
begin | |
SetConvFactorUnit1; | |
bModified := True; | |
end; | |
procedure TConfigdlg.CheckBox1Click(Sender: TObject); | |
begin | |
EnableCh1; | |
bModified := True; bCh1Changed := True; | |
end; | |
procedure TConfigdlg.CheckBox2Click(Sender: TObject); | |
begin | |
EnableCh2; | |
bModified := True; bCh2Changed := True; | |
end; | |
procedure TConfigdlg.CheckBox3Click(Sender: TObject); | |
begin | |
EnableCh3; | |
bModified := True; | |
bCh3Changed := True; | |
end; | |
procedure TConfigdlg.CheckBox4Click(Sender: TObject); | |
begin | |
EnableCh4; | |
bModified := True; | |
bCh4Changed := True; | |
end; | |
procedure TConfigdlg.SpeedButton1Click(Sender: TObject); | |
begin | |
Mainform.Configuration.GetMaxFrameRate(SpinEdit1.Value, SpinEdit2.Value, newFrameRate, newPixelRate); | |
bBlockEdit9Change := True; | |
Edit9.Text := Format('%f', [newFrameRate]); | |
bBlockEdit9Change := False; | |
OnPixelRateChanged; | |
bModified := True; | |
end; | |
procedure TConfigdlg.Button1Click(Sender: TObject); | |
begin | |
SpinEdit1.Value := 500; | |
SpinEdit2.Value := 500; | |
SpinEdit3.Value := 0; | |
SpinEdit4.Value := 0; | |
Edit9.Text := '4'; | |
CheckBox1.Enabled := True; | |
ComboBox2.ItemIndex := 0; | |
CheckBox2.Enabled := False; | |
CheckBox3.Enabled := False; | |
CheckBox4.Enabled := False; | |
bModified := True; | |
end; | |
resourcestring | |
sFrameWidthNotOK = 'Frame width must be between 10 and 500.'; | |
sFrameHeightNotOK = 'Frame height must be between 10 and 500.'; | |
sFrameXOffsetNotOK = 'Frame X-offset must be between 0 and 490.'; | |
sFrameYOffsetNotOK = 'Frame Y-offset must be between 0 and 490.'; | |
sFrameRateNotOK = 'Invalid Frame Rate.'; | |
sVideoChCountNotOK = 'At least one video channel must be enabled.'; | |
sDataPtsPerFrameNotOKCh1 = 'Invalid number of data points / frame in Analog Ch 1.'; | |
sDataPtsPerFrameNotOKCh2 = 'Invalid number of data points / frame in Analog Ch 2.'; | |
sFrameTooSmall = 'Selected frame is too small.' + CRLF + | |
'Frames must have at least 512 pixels.'; | |
procedure TConfigdlg.BitBtn1Click(Sender: TObject); | |
var bValueOK: boolean; | |
fh: integer; | |
begin | |
bValueOK := True; | |
if bModified then | |
try | |
with mainform.Configuration do | |
begin | |
{Test critical parameters} | |
if bValueOK and bFrameWidthChanged then bValueOK := ValidateFrameWidth(SpinEdit1.Value); | |
if not bValueOK then | |
begin | |
MessageDlg(sFrameWidthNotOK, mtError, [mbOK], 0); | |
SpinEdit1.Value := FrameWidth; | |
PageControl1.ActivePage := TabSheet1; | |
end; | |
fh := SpinEdit2.Value; | |
if bValueOK and bFrameHeightChanged then bValueOK := ValidateFrameHeight(fh); | |
if not bValueOK then | |
begin | |
MessageDlg(sFrameHeightNotOK, mtError, [mbOK], 0); | |
SpinEdit2.Value := FrameHeight; | |
PageControl1.ActivePage := TabSheet1; | |
end | |
else | |
SpinEdit2.Value := fh; | |
{for double-buffered DMA using the FIFO buffer, the number of samples | |
transferred by WFM_Load must be larger than 2048 samples = 2 channels | |
* 2 frames * total number of pixels} | |
if bValueOK then | |
if Muldiv(SpinEdit1.Value, 5, 4) * SpinEdit2.Value < 512 then | |
begin | |
MessageDlg(sFrameTooSmall, mtError, [mbOK], 0); | |
PageControl1.ActivePage := TabSheet1; | |
bValueOK := False; | |
end; | |
if bValueOK and bFrameXOffsetChanged then bValueOK := ValidateXOffset(SpinEdit3.Value); | |
if not bValueOK then | |
begin | |
MessageDlg(sFrameXOffsetNotOK, mtError, [mbOK], 0); | |
SpinEdit3.Value := XFrameOffset; | |
PageControl1.ActivePage := TabSheet1; | |
end; | |
if bValueOK and bFrameYOffsetChanged then bValueOK := ValidateYOffset(SpinEdit4.Value); | |
if not bValueOK then | |
begin | |
MessageDlg(sFrameYOffsetNotOK, mtError, [mbOK], 0); | |
SpinEdit4.Value := YFrameOffset; | |
PageControl1.ActivePage := TabSheet1; | |
end; | |
if bValueOK and bFrameRateChanged then bValueOK := ValidateFrameRate(StrToFloat(Edit9.Text)); | |
if not bValueOK then | |
begin | |
MessageDlg(sFrameRateNotOK, mtError, [mbOK], 0); | |
Edit9.Text := Format('%f', [FrameRate]); | |
PageControl1.ActivePage := TabSheet1; | |
end; | |
if bValueOK and (bCh1Changed or bCh2Changed) then bValueOK := ValidateVideoChs; | |
if not bValueOK then | |
begin | |
MessageDlg(sVideoChCountNotOK, mtError, [mbOK], 0); | |
CheckBox1.Checked := True; | |
PageControl1.ActivePage := TabSheet2; | |
end; | |
if bValueOK and bCh3DataPtsChanged then bValueOK := ValidateDataPtsCh(SpinEdit6.Value); | |
if not bValueOK then | |
begin | |
MessageDlg(sDataPtsPerFrameNotOKCh1, mtError, [mbOK], 0); | |
SpinEdit6.Value := ChDataPtsPerFrames[2]; | |
PageControl1.ActivePage := TabSheet4; | |
end; | |
if bValueOK and bCh4DataPtsChanged then bValueOK := ValidateDataPtsCh(SpinEdit5.Value); | |
if not bValueOK then | |
begin | |
MessageDlg(sDataPtsPerFrameNotOKCh2, mtError, [mbOK], 0); | |
SpinEdit5.Value := ChDataPtsPerFrames[3]; | |
PageControl1.ActivePage := TabSheet5; | |
end; | |
if bValueOK then | |
begin | |
{Saves current configuration} | |
CopyTo(Mainform.prevConfig); | |
{stuff results back} | |
FrameWidth := SpinEdit1.Value; | |
FrameHeight := (SpinEdit2.Value div 2) * 2; {even number of lines} | |
XFrameOffset := SpinEdit3.Value; | |
YFrameOffset := SpinEdit4.Value; | |
PixelClock := newPixelRate; | |
ChEnabled[0] := CheckBox1.Checked; | |
ChNames[0] := Edit1.Text; | |
ChInputRanges[0] := TFullScaleVal(ComboBox2.ItemIndex); | |
ChEnabled[1] := CheckBox2.Checked; | |
ChNames[1] := Edit2.Text; | |
ChInputRanges[1] := TFullScaleVal(ComboBox1.ItemIndex); | |
ChEnabled[2] := CheckBox3.Checked; | |
ChNames[2] := Edit3.Text; | |
ChInputRanges[2] := TFullScaleVal(ComboBox3.ItemIndex); | |
ChUnits[2] := Edit5.Text; | |
ChPrefixes[2] := TPrefix(ComboBox4.ItemIndex); | |
ChOffsets[2] := StrToFloat(Edit4.Text); | |
ChDataPtsPerFrames[2] := SpinEdit6.Value; | |
ChEnabled[3] := CheckBox4.Checked; | |
ChNames[3] := Edit6.Text; | |
ChInputRanges[3] := TFullScaleVal(ComboBox5.ItemIndex); | |
ChUnits[3] := Edit7.Text; | |
ChPrefixes[3] := TPrefix(ComboBox6.ItemIndex); | |
ChOffsets[3] := StrToFloat(Edit11.Text); | |
ChDataPtsPerFrames[3] := SpinEdit5.Value; | |
ModalResult := mrOK; | |
end | |
else | |
ModalResult := mrNone; | |
end; | |
except | |
ModalResult := mrNone; | |
if bValueOK then Raise; {show the original error message} | |
end; | |
end; | |
procedure TConfigdlg.SpinEdit1Change(Sender: TObject); | |
begin | |
bModified := True; bFrameWidthChanged := True; | |
end; | |
procedure TConfigdlg.SpinEdit2Change(Sender: TObject); | |
begin | |
bModified := True; bFrameHeightChanged := True; | |
end; | |
procedure TConfigdlg.SpinEdit3Change(Sender: TObject); | |
begin | |
bModified := True; bFrameXOffsetChanged := True; | |
end; | |
procedure TConfigdlg.SpinEdit4Change(Sender: TObject); | |
begin | |
bModified := True; bFrameYOffsetChanged := True; | |
end; | |
procedure TConfigdlg.Edit9Change(Sender: TObject); | |
begin | |
if bBlockEdit9Change then Exit; | |
bModified := True; bFrameRateChanged := True; | |
if Mainform.Configuration.FrameRateToPixelRate | |
(StrToFloat(Edit9.Text), SpinEdit1.Value, SpinEdit2.Value, newPixelRate) then | |
begin | |
Mainform.Configuration. | |
PixelRateToFrameRate(newPixelRate, SpinEdit1.Value, SpinEdit2.Value, newFrameRate); | |
bBlockEdit9Change := True; | |
Edit9.Text := Format('%f', [newFrameRate]); | |
bBlockEdit9Change := False; | |
OnPixelRateChanged; | |
end; | |
end; | |
procedure TConfigdlg.Edit1Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.ComboBox2Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.Edit2Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.ComboBox1Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.Edit3Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.ComboBox3Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.Edit10Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.Edit4Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.SpinEdit6Change(Sender: TObject); | |
begin | |
bModified := True; bCh3DataPtsChanged := True; | |
Label28.Caption := Format('%5f', [newFrameRate * SpinEdit6.Value]); | |
end; | |
procedure TConfigdlg.Edit6Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.ComboBox5Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.Edit8Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.Edit11Change(Sender: TObject); | |
begin | |
bModified := True; | |
end; | |
procedure TConfigdlg.SpinEdit5Change(Sender: TObject); | |
begin | |
bModified := True; bCh4DataPtsChanged := True; | |
Label37.Caption := Format('%5f', [newFrameRate * SpinEdit5.Value]); | |
end; | |
procedure TConfigdlg.SpinButton1DownClick(Sender: TObject); | |
var freq: double; | |
bChangingPixelRate: boolean; | |
changedPixelRate: integer; | |
begin | |
try | |
freq := StrToFloat(Edit9.Text); | |
if freq < 1 then Exit; | |
bChangingPixelRate := False; | |
repeat | |
freq := freq - 1; | |
if freq >= 0.5 then | |
begin | |
Mainform.Configuration.FrameRateToPixelRate | |
(freq, SpinEdit1.Value, SpinEdit2.Value, changedPixelRate); | |
if (changedPixelRate <> newPixelRate) then bChangingPixelRate := True; | |
end; | |
until bChangingPixelRate or (freq < 0.5); | |
if bChangingPixelRate then | |
begin | |
newPixelRate := changedPixelRate; | |
OnPixelRateChanged; | |
Mainform.Configuration.PixelRateToFrameRate | |
(newPixelRate, SpinEdit1.Value, SpinEdit2.Value, newFrameRate); | |
bBlockEdit9Change := True; | |
Edit9.Text := Format('%f', [newFrameRate]); | |
bBlockEdit9Change := False; | |
end; | |
except | |
mainform.Configuration.GetMaxFrameRate(SpinEdit1.Value, SpinEdit2.Value, newFrameRate, newPixelRate); | |
bBlockEdit9Change := True; | |
Edit9.Text := Format('%f', [newFrameRate]); | |
OnPixelRateChanged; | |
bBlockEdit9Change := False; | |
end; | |
bModified := True; bFrameRateChanged := True; | |
end; | |
procedure TConfigdlg.SpinButton1UpClick(Sender: TObject); | |
var freq: double; | |
bChangingPixelRate: boolean; | |
changedPixelRate: integer; | |
begin | |
try | |
freq := StrToFloat(Edit9.Text); | |
if freq > 1000 then Exit; | |
bChangingPixelRate := False; | |
repeat | |
freq := freq + 1; | |
if freq < 1000 then | |
begin | |
Mainform.Configuration.FrameRateToPixelRate | |
(freq, SpinEdit1.Value, SpinEdit2.Value, changedPixelRate); | |
if (changedPixelRate <> newPixelRate) then bChangingPixelRate := True; | |
end; | |
until bChangingPixelRate or (freq >= 1000); | |
if bChangingPixelRate then | |
begin | |
newPixelRate := changedPixelRate; | |
OnPixelRateChanged; | |
Mainform.Configuration.PixelRateToFrameRate | |
(newPixelRate, SpinEdit1.Value, SpinEdit2.Value, newFrameRate); | |
bBlockEdit9Change := True; | |
Edit9.Text := Format('%f', [newFrameRate]); | |
bBlockEdit9Change := False; | |
end; | |
except | |
mainform.Configuration.GetMaxFrameRate(SpinEdit1.Value, SpinEdit2.Value, newFrameRate, newPixelRate); | |
bBlockEdit9Change := True; | |
Edit9.Text := Format('%f', [newFrameRate]); | |
bBlockEdit9Change := False; | |
OnPixelRateChanged; | |
end; | |
bModified := True; bFrameRateChanged := True; | |
end; | |
procedure TConfigdlg.SpinButton2DownClick(Sender: TObject); | |
begin | |
if newPixelRate > 8 then newPixelRate := newPixelRate - 1; | |
if not Mainform.Configuration.PixelRateToFrameRate | |
(newPixelRate, SpinEdit1.Value, SpinEdit2.Value, newFrameRate) then | |
MessageDlg('Pixel Rate too fast for X- mirror to follow.', mtInformation, [mbOK], 0); | |
bModified := True; bFrameRateChanged := True; | |
bBlockEdit9Change := True; | |
Edit9.Text := Format('%f', [newFrameRate]); | |
bBlockEdit9Change := False; | |
OnPixelRateChanged; | |
end; | |
procedure TConfigdlg.SpinButton2UpClick(Sender: TObject); | |
begin | |
if newPixelRate < 999 then newPixelRate := newPixelRate + 1; | |
if not Mainform.Configuration.PixelRateToFrameRate | |
(newPixelRate, SpinEdit1.Value, SpinEdit2.Value, newFrameRate) then | |
MessageDlg('Pixel Rate too fast for X- mirror to follow.', mtInformation, [mbOK], 0); | |
bBlockEdit9Change := True; | |
Edit9.Text := Format('%f', [newFrameRate]); | |
bBlockEdit9Change := False; | |
bModified := True; bFrameRateChanged := True; | |
OnPixelRateChanged; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit FrameOpDlgu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
StdCtrls, Buttons, ExtCtrls, Spin; | |
type | |
TFrameOpDlg = class(TForm) | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
GroupBox1: TGroupBox; | |
RadioButton1: TRadioButton; | |
RadioButton2: TRadioButton; | |
SpinEdit1: TSpinEdit; | |
SpinEdit2: TSpinEdit; | |
Label1: TLabel; | |
Label2: TLabel; | |
GroupBox2: TGroupBox; | |
Label3: TLabel; | |
ComboBox1: TComboBox; | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
end; | |
var | |
FrameOpDlg: TFrameOpDlg; | |
implementation | |
{$R *.DFM} | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit galiltestfrm; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, DMCCom40u, | |
StdCtrls, Buttons; | |
type | |
TForm1 = class(TForm) | |
Label1: TLabel; | |
BitBtn1: TBitBtn; | |
Edit1: TEdit; | |
Label2: TLabel; | |
Label3: TLabel; | |
BitBtn2: TBitBtn; | |
Label4: TLabel; | |
BitBtn3: TBitBtn; | |
Edit2: TEdit; | |
Label5: TLabel; | |
BitBtn4: TBitBtn; | |
BitBtn5: TBitBtn; | |
BitBtn6: TBitBtn; | |
Edit3: TEdit; | |
Edit4: TEdit; | |
Edit5: TEdit; | |
Label6: TLabel; | |
Label7: TLabel; | |
Label8: TLabel; | |
BitBtn7: TBitBtn; | |
BitBtn8: TBitBtn; | |
Label9: TLabel; | |
Label10: TLabel; | |
Label11: TLabel; | |
Label12: TLabel; | |
Label13: TLabel; | |
Label14: TLabel; | |
procedure FormCreate(Sender: TObject); | |
procedure FormClose(Sender: TObject; var Action: TCloseAction); | |
procedure BitBtn1Click(Sender: TObject); | |
procedure BitBtn2Click(Sender: TObject); | |
procedure BitBtn3Click(Sender: TObject); | |
procedure BitBtn4Click(Sender: TObject); | |
procedure BitBtn5Click(Sender: TObject); | |
procedure BitBtn6Click(Sender: TObject); | |
procedure BitBtn7Click(Sender: TObject); | |
procedure BitBtn8Click(Sender: TObject); | |
private | |
{ Private declarations } | |
inputstring, outputstring: String; | |
initialCounts, initialPositions: array[0..2] of integer; | |
public | |
{ Public declarations } | |
libHandle: THandle; | |
controllerHandle: integer; | |
DMCOpen: TDMCOpen; | |
DMCClose: TDMCClose; | |
DMCCommand: TDMCCommand; | |
DMCWaitForMotionComplete: TDMCWaitForMotionComplete; | |
end; | |
var | |
Form1: TForm1; | |
implementation | |
{$R *.DFM} | |
procedure TForm1.FormCreate(Sender: TObject); | |
var retval: integer; | |
freq: TLargeInteger; | |
s2, s3: string; | |
begin | |
libHandle := LoadLibrary('dmc32.dll'); | |
if libHandle <> 0 then | |
begin | |
DMCOpen := GetProcAddress(libHandle, 'DMCOpen'); | |
DMCClose := GetProcAddress(libHandle, 'DMCClose'); | |
DMCCommand := GetProcAddress(libHandle, 'DMCCommand'); | |
DMCWaitForMotionComplete := GetProcAddress(libHandle, 'DMCWaitForMotionComplete'); | |
if Assigned(DMCOpen) then | |
begin | |
retval := DMCOpen(1, 0, controllerHandle); | |
if retval = 0 then | |
begin | |
Label1.Caption := 'Controller OK'; | |
SetLength(outputstring, 128); | |
inputstring := 'HX 0;MT -2,-2,-2;CE 0,0,0,0;YA 16,16,16;YB 400,400,400;SP 3000,3000,3000;LD 0,0,0;CN -1,-1,-1,0,0;OB 1,1;OB 2,1;OB 3,1'; | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
Label3.Caption := outputString; | |
{finds initial counts and position} | |
inputstring := 'PA ?,?,?'; | |
IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
initialCounts[0] := StrToInt(Copy(outputString, 2, Pos(',', outputString) - 2)); | |
s2 := Copy(outputString, Pos(',', outputString) + 1, Pos(':', outputString) - Pos(',', outputString)); | |
initialCounts[1] := StrToInt(Copy(s2, 2, Pos(',', s2) - 2)); | |
s3 := Copy(s2, Pos(',', s2) + 1, Pos(Chr(13), s2) - Pos(',', s2)); | |
initialCounts[2] := StrToInt(Copy(s3, 2, Pos(Chr(13), s3) - 2)); | |
inputstring := 'TPABC'; | |
IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
initialPositions[0] := StrToInt(Copy(outputString, 2, Pos(',', outputString) - 2)); | |
s2 := Copy(outputString, Pos(',', outputString) + 1, Pos(':', outputString) - Pos(',', outputString)); | |
initialPositions[1] := StrToInt(Copy(s2, 2, Pos(',', s2) - 2)); | |
s3 := Copy(s2, Pos(',', s2) + 1, Pos(Chr(13), s2) - Pos(',', s2)); | |
initialPositions[2] := StrToInt(Copy(s3, 2, Pos(Chr(13), s3) - 2)); | |
Label9.Caption := IntToStr(initialCounts[0]); | |
Label10.Caption := IntToStr(initialCounts[1]); | |
Label11.Caption := IntToStr(initialCounts[2]); | |
Label12.Caption := IntToStr(initialPositions[0]); | |
Label13.Caption := IntToStr(initialPositions[1]); | |
Label14.Caption := IntToStr(initialPositions[2]); | |
end | |
else | |
Label1.Caption := 'Controller Failed: ' + IntToStr(retval); | |
end; | |
{opens galil} | |
end; | |
QueryPerformanceFrequency(freq); | |
Label5.Caption := IntToStr(freq); | |
end; | |
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); | |
begin | |
if Assigned(DMCClose) then | |
begin | |
inputstring := 'XQ 0'; | |
SetLength(outputstring, 1024); | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
DMCClose(controllerHandle); | |
end; | |
FreeLibrary(libHandle); | |
end; | |
procedure TForm1.BitBtn1Click(Sender: TObject); | |
begin | |
SetLength(outputstring, 64); | |
inputstring := 'PR ,,' + Edit1.Text + ';BGZ'; | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
Label3.Caption := outputString; | |
inputString := 'XYZ'; | |
Label2.Caption := IntToStr(DMCWaitForMotionComplete(controllerHandle, PChar(inputstring), 1)); | |
BitBtn2Click(nil); | |
end; | |
procedure TForm1.BitBtn2Click(Sender: TObject); | |
begin | |
inputstring := 'TP'; | |
SetLength(outputstring, 1024); | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 1024)); | |
Label4.Caption := outputString; | |
Edit2.Text := outputString; | |
end; | |
procedure TForm1.BitBtn3Click(Sender: TObject); | |
begin | |
inputstring := 'ST;'; | |
SetLength(outputstring, 1024); | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 1024)); | |
Label4.Caption := outputString; | |
end; | |
procedure TForm1.BitBtn4Click(Sender: TObject); | |
begin | |
SetLength(outputstring, 64); | |
inputstring := 'PAA=' + | |
IntToStr(initialCounts[0] - Muldiv(16, 10 * StrToInt(Edit3.Text) - InitialPositions[0], 50)) | |
+ ';BGA'; | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
Label3.Caption := outputString; | |
inputString := 'X'; | |
Label2.Caption := IntToStr(DMCWaitForMotionComplete(controllerHandle, PChar(inputstring), 1)); | |
end; | |
procedure TForm1.BitBtn5Click(Sender: TObject); | |
begin | |
SetLength(outputstring, 64); | |
inputstring := 'PAB=' + | |
IntToStr(initialCounts[1] - Muldiv(16, 10 * StrToInt(Edit4.Text) - InitialPositions[1], 50)) | |
+ ';BGB'; | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
Label3.Caption := outputString; | |
inputString := 'Y'; | |
Label2.Caption := IntToStr(DMCWaitForMotionComplete(controllerHandle, PChar(inputstring), 1)); | |
end; | |
procedure TForm1.BitBtn6Click(Sender: TObject); | |
begin | |
SetLength(outputstring, 64); | |
inputstring := 'PAC=' + | |
IntToStr(initialCounts[2] - Muldiv(16, 10 * StrToInt(Edit5.Text) - InitialPositions[2], 50)) | |
+ ';BGC'; | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
Label3.Caption := outputString; | |
inputString := 'Z'; | |
Label2.Caption := IntToStr(DMCWaitForMotionComplete(controllerHandle, PChar(inputstring), 1)); | |
end; | |
procedure TForm1.BitBtn7Click(Sender: TObject); | |
begin | |
SetLength(outputstring, 64); | |
inputstring := 'PA ?,?,?'; | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
Edit1.Text := outputString; | |
end; | |
procedure TForm1.BitBtn8Click(Sender: TObject); | |
begin | |
SetLength(outputstring, 64); | |
inputstring := 'PAA=' + | |
Edit3.Text | |
+ ';BGA'; | |
Label2.Caption := IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
Label3.Caption := outputString; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit GalilThreadU; | |
{Manages the Galil DMC-40 controller} | |
{$ASSERTIONS ON} | |
interface | |
uses | |
Classes, Windows, DMCCom40u, StrUtils, Dialogs; | |
type | |
TGALIL_Action = | |
(GALIL_NO_ACTION, | |
GALIL_SET_XY_SPEED, | |
GALIL_SET_Z_SPEED, | |
GALIL_GET_Z, | |
GALIL_SET_Z, | |
GALIL_SET_TO_RELATIVE_Z, | |
GALIL_SET_TO_RELATIVE_Z_NO_UPDATE, {for stacks} | |
GALIL_MOVE_TO_Z, | |
GALIL_READ_Z, | |
{GALIL_SHIFT_BY_Z, (not used)} | |
GALIL_GET_XY, | |
GALIL_SET_XY, | |
GALIL_SET_TO_RELATIVE_XY, | |
GALIL_MOVE_TO_XY, | |
GALIL_READ_XY, | |
GALIL_SHIFT_BY_XY, | |
GALIL_FAST_STACK, | |
GALIL_COMMAND); | |
TGalilThread = class(TThread) | |
private | |
// Galil function variables | |
fbConnected: boolean; | |
libHandle: THandle; | |
DMCOpen: TDMCOpen; | |
DMCClose: TDMCClose; | |
inputstring, outputstring: string; | |
initialCounts, initialPositions: array[0..2] of integer; | |
stepsToMoveZafterFastStack: integer; | |
posBeforeFastStackCountsZ: string; | |
speedBeforeFastStackZ: string; | |
procedure UpdateUserInterfaceZ; | |
procedure UpdateUserInterfaceXY; | |
procedure UnloadGALILLibrary; | |
public | |
controllerHandle: integer; // 8-6-09 ALS - made public | |
DMCCommand: TDMCCommand; // 8-6-09 ALS - made public | |
DMCWaitForMotionComplete: TDMCWaitForMotionComplete; // 8-6-09 - made public | |
DMCSetTimeout: TDMCSetTimeout; // 8-6-09 ALS - new function | |
GalilAction : TGALIL_Action; | |
GalilParam1, GalilParam2: double; | |
zSpeedBeforeFastStack: double; // keep track of this, for resetting after fast stack | |
//jdz - used to pass values into the fast stack, which is actually | |
// executed as a thread | |
fastStackInterval: double; // in microns - not used | |
fastStackSpeed: double; // in microns per second, will be 1-60 | |
fastStackDistance: double; // distance for fast stack, in microns | |
GalilCommandString: string; | |
procedure GetXY(var x, y: integer); //jd - moved to public | |
procedure GetZ(var z: double); //jd - moved to public | |
procedure ConnectToGALIL; | |
procedure Execute; override; | |
procedure WaitForMotionComplete; //PB | |
procedure ResetSpeedAndPosAfterFastStackZ; //jdz used to return the stage to the previous speed after fast stack | |
constructor Create(CreateSuspended: boolean); | |
destructor Destroy; override; | |
property Connected: boolean read fbConnected; | |
function InMotionZ: boolean; // true if the stage is moving in Z | |
procedure StopMotion; //jd - halt motion | |
end; | |
implementation | |
uses Sysutils, Math, MPUnit, mpdevices; | |
const | |
ENCODER_RESOLUTION_Z = 0.1; {0.1 micron} | |
ENCODER_RESOLUTION_XY = 1.0; // RIG - 1.0 for both Laser RM1 rigs, 0.1 for Laser RM2 | |
EPSILON_XY = 16 div 5; {close-loop will tolerate error EPSILON_XY of ~ 1 micron} | |
// original line from March 2009 ... removing most setup parameters, | |
// which are set when the joystick code executies, | |
// so this code is more universal | |
//sGalilStart = 'HX 0;MT=-2,-2,-2;CE 0,0,0;YA 16,16,16;YB 400,400,400;LD 0,0,0;OB 1,1;OB 2,1;OB 3,1;AC=10000,10000,10000;DC=10000,10000,10000;'; | |
// sGalilStart = 'HX 0;CE 0,0,0;OB 1,1;OB 2,1;OB 3,1;'; | |
// sGalilStart = 'HX 0;OB 1,1;OB 2,1;OB 3,1;'; // 7-29-09 ALS | |
sGalilStart = 'HX;XQ #limtest,0;OB 1,1;OB 2,1;OB 3,1;LD 0,0,0'; //PB 7-31-09 | |
sGalilEnd = 'OB 1,0;OB 2,0;OB 3,0;HX;ST;MO;XQ #AUTO'; | |
sSetupMoveCommandRZ = 'SPC=%s;ACC=%s;DCC=%s;PRC=%s;BGZ'; | |
sSetupMoveCommandAZ = 'SPC=%s;ACC=%s;DCC=%s;PAC=%s;BGZ'; | |
sMoveCompleteZ = 'C'; | |
sResumeZ = 'OB 3,0;XQ 0'; | |
sSetupMoveCommandRXY = 'SP %s,%s;AC %s,%s;DC %s,%s;PR %s,%s;BG AB;'; | |
sSetupMoveCommandAXY = 'SP %s,%s;AC %s,%s;DC %s,%s;PA %s,%s;BG AB;'; | |
sMoveCompleteXY = 'AB'; | |
sResumeXY = 'OB 1,0;OB 2,0;XQ 0'; | |
// move relative lines are not currently used | |
//sMoveRelativeXY = 'OB 1,1;OB 2,1;PR %s,%s;BGXY;'; | |
//sMoveRelativeZ = 'OB 3,1;PR ,,%s;BGZ;'; | |
sSetZSpeed = 'SPC=%s'; | |
sResumeExecution: PChar = 'XQ 0'; | |
sFastStackMoveRZ = 'PRZ=%s;BGZ'; //PB | |
MIN_XY_SPEED = 200; {arbitrary limit on speed (in MICROSTEPS! counts/s)} | |
MAX_XY_SPEED = 20000; //PB | |
MIN_Z_SPEED = 200; | |
MAX_Z_SPEED = 20000; //PB | |
MIN_XY_ACC = 1000; {acceleration and deceleration have to match speed and load???} | |
MIN_XY_DEC = 1000; | |
MIN_Z_ACC = 1000; | |
MIN_Z_DEC = 1000; | |
GALIL_READ_DELAY = 100; {in ms} | |
procedure TGalilThread.ResetSpeedAndPosAfterFastStackZ; | |
begin | |
// function is used to Reset the Speed, and also return the Z to the | |
// original position (before a fast stack) | |
// !!! do not call this function without calling FAST_STACK first, | |
// since the output strings will be set to junk! | |
WaitForMotionComplete; | |
//inputString := 'SPZ= 5000'; | |
//DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
// reset the speed | |
inputString := 'SPZ= ' + speedBeforeFastStackZ + ';'; | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
// also reset postion | |
inputString := 'PAZ= ' + posBeforeFastStackCountsZ + ';BGZ;'; | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
end; | |
procedure TGalilThread.StopMotion; | |
begin | |
inputString := 'ST XYZ'; | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
end; | |
//jdz | |
function TGalilThread.InMotionZ: boolean; | |
var | |
c: AnsiChar; | |
str: string; | |
begin | |
SetLength(outputstring, 128); | |
inputstring := 'MG _BGZ'; | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
//messageBox(0,pchar(outputString),'',0); | |
// 'MG _BGZ' returns 1 is in motion, 0 otherwise | |
Result := false; | |
str := Copy(outputString,2,1); // character will be 1 or 0, depending on motion | |
if str = '1' then Result := true; | |
//if Result then messageBox(0,'moving','',0) | |
//else messageBox(0,'stopped','not moving',0); | |
//messageBox(0,'test',outputString,0); | |
end; | |
procedure TGalilThread.GetZ(var z: double); | |
begin | |
// wait for motion to complete and add a delay, | |
// this keep the updated position correct, | |
// but keeps you from rapidly pressing the move button | |
// - don't use delay | |
//DMCWaitForMotionComplete(controllerHandle, 'Z', FALSE); | |
//Delay(GALIL_READ_DELAY); // small delay to make sure motion has settled | |
SetLength(outputstring, 128); | |
inputstring := 'TP C'; | |
if DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128) = 0 then | |
try | |
{convert to microns; encoders are 0.1 um - Galil returns string ' 1234:CR'} | |
z := ENCODER_RESOLUTION_Z * StrToFloat(Copy(outputString, 2, Pos(':', outputString) - 4)); | |
except | |
z := 0; | |
end; | |
end; | |
procedure TGalilThread.GetXY(var x, y: integer); | |
begin | |
// wait for motion to complete and add a delay, | |
// this keep the updated position correct, | |
// but keeps you from rapidly pressing the move button | |
DMCWaitForMotionComplete(controllerHandle, 'XY', FALSE); | |
Delay(GALIL_READ_DELAY); // small delay to make sure motion has settled | |
SetLength(outputstring, 128); | |
inputstring := 'TP AB'; | |
if DMCCommand(controllerHandle, PChar(inputstring), PChar(outputstring), 128) = 0 then | |
try | |
{convert to microns} | |
x := Round(ENCODER_RESOLUTION_XY * StrToFloat(Copy(outputString, 2, Pos(',', outputString) - 2))); | |
y := Round(ENCODER_RESOLUTION_XY * StrToFloat(Copy(outputString, Pos(',', outputString) + 2, Pos(':', outputString) - Pos(',', outputString) - 4))); | |
except | |
x := 0; y := 0; | |
end; | |
//MessageBox(0,pchar(floatToStr(x)),pchar(floatToStr(y)),0); | |
end; | |
procedure TGalilThread.WaitForMotionComplete; | |
begin | |
DMCWaitForMotionComplete(controllerHandle, 'XYZ', FALSE); | |
end; | |
procedure TGalilThread.ConnectToGALIL; | |
var s2, s3: string; | |
begin | |
libHandle := LoadLibrary('dmc32.dll'); | |
if libHandle <> 0 then | |
begin | |
DMCOpen := GetProcAddress(libHandle, 'DMCOpen'); // get function pointer from DLL | |
DMCClose := GetProcAddress(libHandle, 'DMCClose'); | |
DMCCommand := GetProcAddress(libHandle, 'DMCCommand'); | |
DMCWaitForMotionComplete := GetProcAddress(libHandle, 'DMCWaitForMotionComplete'); | |
DMCSetTimeout := GetProcAddress(libHandle, 'DMCSetTimeout'); // 8-6-09 ALS | |
if Assigned(DMCOpen) then | |
fbConnected := (DMCOpen(1, 0, controllerHandle) = 0); // controller #1 default | |
if fbConnected then | |
begin | |
{sets up Galil default parameters} | |
inputString := sGalilStart; | |
SetLength(outputstring, 128); | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
{finds initial stepper counts and position} | |
inputstring := 'PA ?,?,?'; | |
IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
initialCounts[0] := StrToInt(Copy(outputString, 2, Pos(',', outputString) - 2)); | |
s2 := Copy(outputString, Pos(',', outputString) + 1, Pos(':', outputString) - Pos(',', outputString)); | |
initialCounts[1] := StrToInt(Copy(s2, 2, Pos(',', s2) - 2)); | |
s3 := Copy(s2, Pos(',', s2) + 1, Pos(Chr(13), s2) - Pos(',', s2)); | |
initialCounts[2] := StrToInt(Copy(s3, 2, Pos(Chr(13), s3) - 2)); | |
inputstring := 'TPABC'; | |
IntToStr(DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64)); | |
initialPositions[0] := StrToInt(Copy(outputString, 2, Pos(',', outputString) - 2)); | |
s2 := Copy(outputString, Pos(',', outputString) + 1, Pos(':', outputString) - Pos(',', outputString)); | |
initialPositions[1] := StrToInt(Copy(s2, 2, Pos(',', s2) - 2)); | |
s3 := Copy(s2, Pos(',', s2) + 1, Pos(Chr(13), s2) - Pos(',', s2)); | |
initialPositions[2] := StrToInt(Copy(s3, 2, Pos(Chr(13), s3) - 2)); | |
end; | |
end; | |
end; | |
procedure TGalilThread.UnloadGalilLibrary; | |
begin | |
if libHandle = 0 then Exit; | |
if Assigned(DMCClose) then | |
begin | |
inputString := sGalilEnd; | |
SetLength(outputstring, 128); | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
//Delay(100); // wait to make sure characters have been sent | |
DMCClose(controllerHandle); | |
end; | |
FreeLibrary(libHandle); | |
end; | |
{ Important: Methods and properties of objects in VCL can only be used in a | |
method called using Synchronize, for example, | |
Synchronize(UpdateCaption); | |
and UpdateCaption could look like, | |
procedure TXPSThread.UpdateCaption; | |
begin | |
Form1.Caption := 'Updated in a thread'; | |
end; } | |
procedure TGalilThread.UpdateUserInterfaceZ; | |
begin | |
ZStepper.OnMoveFinished; | |
end; | |
procedure TGalilThread.UpdateUserInterfaceXY; | |
begin | |
XYTable.OnMoveFinished; | |
end; | |
{ TGalilThread } | |
procedure TGalilThread.Execute; | |
var stepsToMoveX, stepsToMoveY, stepsToMoveZ: integer; | |
begin | |
{ Place thread code here } | |
SetLength(outputstring, 128); | |
while not Terminated do | |
{Loops continuously} | |
{wait for 1000 ms each time} | |
if WaitForSingleObject(dmc40.GalilSemaphore, 1000) = WAIT_OBJECT_0 then | |
begin | |
// xyTable.Busy := True; | |
// zStepper.Busy := True; | |
try | |
case GalilAction of | |
GALIL_SET_Z_SPEED: | |
begin | |
zSpeedBeforeFastStack := GalilParam1; // keep this, to reset the speed | |
inputString := Format(sSetZSpeed, [Round(GalilParam1)]); | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
end; | |
GALIL_GET_Z, GALIL_READ_Z: | |
begin | |
GetZ(ZStepper.fzPosition); | |
Synchronize(UpdateUserInterfaceZ); | |
end; | |
GALIL_SET_Z, GALIL_MOVE_TO_Z: | |
begin | |
//jdz | |
// the only time this function is called is | |
// to return the stages to the original position (after FastStack) | |
// so, change function here to handle this case, to get | |
// fast stack working ... | |
// essentially, do nothing here (except update position) | |
// actual handling of resetting speed and pos is in | |
// ResetSpeedAndPosAfterFastStackZ | |
//messageBox(0,'called GALIL_SET_Z','distance',0); | |
//jdz | |
//WaitForMotionComplete(); //jdz - shouldn't need to do this, should already be complete | |
//inputString := Format(sFastStackMoveRZ, [IntToStr(stepsToMoveZafterFaststack)]); | |
//DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
{convert from microns to steps = 16/5 * (10 * positioninmicrons - initialposition) / 10} | |
//stepsToMoveZ := initialCounts[2] - Muldiv(16, Round(10 * GalilParam1) - InitialPositions[2], 50); //jd - should be tied to GALIL_ENCODER_ | |
{------------ CLOSE LOOP MOTION ---------------} | |
{initial sequence - set speed, absolute move, wait until move over} | |
//inputString := Format(sSetupMoveCommandAZ, [ | |
// IntToStr(Round(MAX_Z_SPEED * Log10(ZStepper.Speed + 1))), | |
// IntToStr(MIN_Z_ACC * ZStepper.Speed), | |
// IntToStr(MIN_Z_DEC * ZStepper.Speed), | |
// IntToStr(stepsToMoveZ)]); | |
//DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
//inputString := sMoveCompleteZ; | |
//jdz - no need for this line? | |
//repeat until DMCWaitForMotionComplete(controllerHandle, PChar(inputstring), FALSE) = 0; | |
{correction until ~ 1 um} | |
{update position in user interface} | |
Delay(GALIL_READ_DELAY); {wait 100 ms} | |
GetZ(ZStepper.fzPosition); | |
Synchronize(UpdateUserInterfaceZ); | |
end; | |
GALIL_SET_TO_RELATIVE_Z, GALIL_SET_TO_RELATIVE_Z_NO_UPDATE {GALIL_SHIFT_BY_Z not used}: | |
begin | |
//jdp - note, this is the call that is made | |
// when a user presses a move stage button (in Z) | |
{convert from microns to steps} | |
stepsToMoveZ := Round(GALIL_STEPPER_RESOLUTION_Z * GalilParam1); | |
{------------ CLOSE LOOP MOTION ---------------} | |
{initial sequence - set speed, relative move, wait until move over} | |
inputString := Format(sSetupMoveCommandRZ, [ | |
IntToStr(Round(MAX_Z_SPEED * Log10(ZStepper.Speed + 1))), | |
IntToStr(MIN_Z_ACC * ZStepper.Speed), | |
IntToStr(MIN_Z_DEC * ZStepper.Speed), | |
IntToStr(stepsToMoveZ)]); | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
inputString := sMoveCompleteZ; | |
//repeat until DMCWaitForMotionComplete(controllerHandle, PChar(inputstring), FALSE) = 0; | |
{correction until ~ 1 um} | |
{update position in user interface} | |
//Delay(GALIL_READ_DELAY); {wait 100 ms} | |
if GalilAction <> GALIL_SET_TO_RELATIVE_Z_NO_UPDATE then | |
begin | |
WaitForMotionComplete; | |
Delay(GALIL_READ_DELAY); // make sure motion is completely settled | |
GetZ(ZStepper.fzPosition); | |
end; | |
Synchronize(UpdateUserInterfaceZ); | |
end; | |
GALIL_GET_XY, GALIL_READ_XY: | |
begin | |
GetXY(XYTable.fXPosition, XYTable.fYPosition); | |
Synchronize(UpdateUserInterfaceXY); | |
end; | |
GALIL_SET_XY, GALIL_MOVE_TO_XY: | |
begin | |
// note - stepsToMoveX should be changed to uses GALIL_ENCODER_RESOLUTION_XY, | |
// but this function is not currently called (can be called from the script) | |
{convert from microns to steps = 16/5 * (10 * positioninmicrons - initialposition) / 10} | |
stepsToMoveX := initialCounts[0] - Muldiv(16, Round(10 * GalilParam1) - InitialPositions[0], 50); | |
stepsToMoveY := initialCounts[1] - Muldiv(16, Round(10 * GalilParam2) - InitialPositions[1], 50); | |
{------------ CLOSE LOOP MOTION ---------------} | |
{initial sequence - brakes off, set speed, relative move, wait until move over} | |
inputString := Format(sSetupMoveCommandAXY, [ | |
IntToStr(Round(MAX_XY_SPEED * Log10(XYTable.Speed + 1))), | |
IntToStr(Round(MAX_XY_SPEED * Log10(XYTable.Speed + 1))), | |
IntToStr(MIN_XY_ACC * XYTable.Speed), | |
IntToStr(MIN_XY_ACC * XYTable.Speed), | |
IntToStr(MIN_XY_DEC * XYTable.Speed), | |
IntToStr(MIN_XY_DEC * XYTable.Speed), | |
IntToStr(stepsToMoveX), | |
IntToStr(stepsToMoveY)]); | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
inputString := sMoveCompleteXY; | |
repeat until DMCWaitForMotionComplete(controllerHandle, PChar(inputstring), FALSE) = 0; | |
{correction until ~ 1 um} | |
{update position in user interface} | |
Delay(GALIL_READ_DELAY); {wait 100 ms} | |
GetXY(XYTable.fXPosition, XYTable.fYPosition); | |
Synchronize(UpdateUserInterfaceXY); | |
end; | |
GALIL_SET_TO_RELATIVE_XY, GALIL_SHIFT_BY_XY: | |
begin | |
//jdp - note, this is the call that is made | |
// when a user presses a move stage button (in X or Y) | |
{convert from microns to steps} | |
stepsToMoveX := Round(GALIL_STEPPER_RESOLUTION_XY * GalilParam1); | |
stepsToMoveY := Round(GALIL_STEPPER_RESOLUTION_XY * GalilParam2); | |
{------------ CLOSE LOOP MOTION ---------------} | |
{initial sequence - brakes off, set speed, relative move, wait until move over} | |
inputString := Format(sSetupMoveCommandRXY, [ | |
IntToStr(Round(MAX_XY_SPEED * Log10(XYTable.Speed + 1))), | |
IntToStr(Round(MAX_XY_SPEED * Log10(XYTable.Speed + 1))), | |
IntToStr(MIN_XY_ACC * XYTable.Speed), | |
IntToStr(MIN_XY_ACC * XYTable.Speed), | |
IntToStr(MIN_XY_DEC * XYTable.Speed), | |
IntToStr(MIN_XY_DEC * XYTable.Speed), | |
IntToStr(stepsToMoveX), | |
IntToStr(stepsToMoveY)]); | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
inputString := sMoveCompleteXY; | |
//repeat until DMCWaitForMotionComplete(controllerHandle, PChar(inputstring), FALSE) = 0; | |
WaitForMotionComplete; | |
{update position in user interface} | |
Delay(GALIL_READ_DELAY); {wait 100 ms} | |
GetXY(XYTable.fXPosition, XYTable.fYPosition); | |
Synchronize(UpdateUserInterfaceXY); | |
end; | |
GALIL_FAST_STACK: | |
begin | |
// find the speed before the fast stack, and save it to a string | |
inputString := 'MG _SPZ'; | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
speedBeforeFastStackZ := Copy(outputString,1, Pos(':', outputString)-3); | |
//speedBeforeFastStackZ := outputString; | |
//messageBox(0,pchar(speedBeforeFastStackZ),'',0); | |
// find the original position before the fast stack, and save it to a string | |
inputString := 'MG _TDZ'; | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
posBeforeFastStackCountsZ := Copy(outputString,1, Pos(':', outputString)-3); | |
//messageBox(0,pchar(posBeforeFastStackCountsZ),'',0); | |
// speed comes from slider on user interface | |
// this is a number from 1-60, which is effectively um / s | |
inputString := Format(sSetZSpeed,[IntToStr(Round(fastStackSpeed * GALIL_STEPPER_RESOLUTION_Z))]); | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
//MessageBox(0,PAnsiChar(inputString),'',0); | |
{convert from microns to steps} | |
stepsToMoveZ := Round(GALIL_STEPPER_RESOLUTION_Z * fastStackDistance); //jdz move 10 mils | |
stepsToMoveZafterFastStack := -stepsToMoveZ; | |
inputString := Format(sFastStackMoveRZ, [IntToStr(stepsToMoveZ)]); | |
DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
//DMCWaitForMotionComplete(controllerHandle, 'Z', FALSE); | |
// move back, and wait until done | |
//inputString := Format(sFastStackMoveRZ, [IntToStr(-stepsToMoveZ)]); | |
//DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 128); | |
//DMCWaitForMotionComplete(controllerHandle, 'Z', FALSE); | |
//messageBox(0,PAnsiChar(FloatToStr(fastStackDistance)),'distance',0); | |
//jdz - disable this, because the controller should not wait until move | |
// has ended (rather, should adjust laser power instead | |
//inputString := sMoveCompleteZ; | |
//repeat Delay(10) until DMCWaitForMotionComplete(controllerHandle, PChar(inputstring), FALSE) = 0; | |
// this controls the return position | |
//ZStepper.ZPosition := ZStepper.ZPosition + GalilParam1; | |
dmc40.FastStackCallback; | |
end; | |
GALIL_COMMAND: | |
//DMCCommand(controllerHandle, PChar(inputstring), PChar(outputString), 64); | |
DMCCommand(controllerHandle, PChar(GalilCommandString), PChar(outputString), 64); | |
end; | |
finally | |
GalilAction := GALIL_NO_ACTION; | |
xyTable.Busy := False; | |
zStepper.Busy := False; | |
end; | |
end; // end loop over not Terminated | |
Destroy; // (Destroy must be called explicitly) | |
end; | |
constructor TGalilThread.Create(CreateSuspended: boolean); | |
begin | |
inherited Create(CreateSuspended); | |
FreeOnTerminate := True; | |
end; | |
destructor TGalilThread.Destroy; | |
begin | |
UnloadGalilLibrary; | |
inherited Destroy; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit Gammafrmu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
StdCtrls, Buttons, ComCtrls, ExtCtrls, mpFileu; | |
type | |
TGammaFrm = class(TForm) | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
CheckBox1: TCheckBox; | |
TrackBar1: TTrackBar; | |
TrackBar2: TTrackBar; | |
Label1: TLabel; | |
Label2: TLabel; | |
Bevel1: TBevel; | |
Label3: TLabel; | |
Label4: TLabel; | |
Label5: TLabel; | |
Label6: TLabel; | |
RadioButton1: TRadioButton; | |
RadioButton2: TRadioButton; | |
RadioButton3: TRadioButton; | |
RadioButton4: TRadioButton; | |
procedure FormPaint(Sender: TObject); | |
procedure TrackBar1Change(Sender: TObject); | |
procedure TrackBar2Change(Sender: TObject); | |
procedure RadioButton1Click(Sender: TObject); | |
private | |
{ Private declarations } | |
histoRect: TRect; | |
oldBlackSliderPos, oldWhiteSliderPos: integer; | |
procedure DrawBlackLevelLine(sliderPos: integer); | |
procedure DrawHistogram; | |
procedure DrawWhiteLevelLine(sliderPos: integer); | |
public | |
{ Public declarations } | |
bInitializing: boolean; | |
mpFile: TMPFile; | |
procedure InitGUI(afile: TMPFile); | |
function SelectedCh: integer; | |
end; | |
var | |
GammaFrm: TGammaFrm; | |
implementation | |
{$R *.DFM} | |
const | |
BORDER_OFFSET = 12; | |
BIN_SIZE = 128; {for histogram} | |
procedure TGammaFrm.DrawBlackLevelLine(sliderPos: integer); | |
var linePos: integer; | |
begin | |
Canvas.Pen.Color := clRed; | |
Canvas.Pen.Width := 1; | |
Canvas.Pen.Style := psSolid; | |
Canvas.Pen.Mode := pmXor; | |
linePos := histoRect.Left + Muldiv(sliderPos, histoRect.Right - histoRect.Left, | |
2047 + 128); | |
Canvas.MoveTo(linePos, histoRect.Top); | |
Canvas.LineTo(linePos, histoRect.Bottom); | |
oldBlackSliderPos := sliderPos; | |
end; | |
procedure TGammaFrm.DrawHistogram; | |
var histogram: array of integer; | |
chIndex, i, maxValue, barValue, leftRect, rightRect: integer; | |
barRect: TRect; | |
begin | |
Canvas.Brush.Color := clWhite; | |
Canvas.FillRect(histoRect); | |
// Get the histogram | |
chIndex := SelectedCh; | |
SetLength(histogram, 2048 div BIN_SIZE + 1); | |
(mpFile.Frames[mpFile.ActiveFrameIndex].channels[chIndex] as TVideoFrame). | |
GetProfile(BIN_SIZE, histogram); | |
maxValue := 0; | |
for i := 0 to 2048 div BIN_SIZE do | |
if histogram[i] > maxValue then maxValue := histogram[i]; | |
// Draws the rectangles | |
Canvas.Brush.Color := clBlack; | |
for i := 0 to 2048 div BIN_SIZE do | |
begin | |
barValue := histoRect.Bottom - Muldiv(histogram[i], | |
histoRect.Bottom - histoRect.Top, maxValue); | |
leftRect := histoRect.Left + Muldiv(i, histoRect.Right - histoRect.Left, | |
2048 div BIN_SIZE + 1); | |
rightRect := histoRect.Left + Muldiv(i + 1, histoRect.Right - histoRect.Left, | |
2048 div BIN_SIZE + 1) - 1; | |
barRect := Rect(leftRect, barValue, rightRect, histoRect.Bottom); | |
Canvas.FillRect(barRect); | |
end; | |
end; | |
procedure TGammaFrm.DrawWhiteLevelLine(sliderPos: integer); | |
var linePos: integer; | |
begin | |
Canvas.Pen.Color := clRed; | |
Canvas.Pen.Width := 1; | |
Canvas.Pen.Style := psSolid; | |
Canvas.Pen.Mode := pmXor; | |
linePos := histoRect.Left + Muldiv(sliderPos, histoRect.Right - histoRect.Left, | |
2047 + 128); | |
Canvas.MoveTo(linePos, histoRect.Top); | |
Canvas.LineTo(linePos, histoRect.Bottom); | |
oldWhiteSliderPos := sliderPos; | |
end; | |
procedure TGammaFrm.FormPaint(Sender: TObject); | |
begin | |
histoRect := Rect(BORDER_OFFSET, TrackBar1.Top + TrackBar1.Height, | |
ClientWidth - BORDER_OFFSET, TrackBar2.Top - 1); | |
DrawHistogram; | |
DrawBlackLevelLine(TrackBar1.Position); | |
DrawWhiteLevelLine(TrackBar2.Position); | |
end; | |
procedure TGammaFrm.TrackBar1Change(Sender: TObject); | |
begin | |
if bInitializing then Exit; | |
Label1.Caption := 'Black Level = ' + IntToStr(TrackBar1.Position - 128); | |
DrawBlackLevelLine(oldBlackSliderPos); | |
DrawBlackLevelLine(TrackBar1.Position); | |
end; | |
procedure TGammaFrm.TrackBar2Change(Sender: TObject); | |
begin | |
if bInitializing then Exit; | |
Label1.Caption := 'White Level = ' + IntToStr(TrackBar2.Position - 128); | |
DrawWhiteLevelLine(oldWhiteSliderPos); | |
DrawWhiteLevelLine(TrackBar2.Position); | |
end; | |
procedure TGammaFrm.RadioButton1Click(Sender: TObject); | |
begin | |
DrawHistogram; | |
DrawBlackLevelLine(TrackBar1.Position); | |
DrawWhiteLevelLine(TrackBar2.Position); | |
end; | |
procedure TGammaFrm.InitGUI(afile: TMPFile); | |
begin | |
with afile do | |
begin | |
RadioButton1.Checked := (DefaultVideoChannel = 0); | |
RadioButton2.Checked := (DefaultVideoChannel = 1); | |
RadioButton3.Checked := (DefaultVideoChannel = 2); | |
RadioButton4.Checked := (DefaultVideoChannel = 3); | |
if VideoChCount = 1 then | |
begin | |
RadioButton1.Enabled := False; | |
RadioButton2.Enabled := False; | |
RadioButton3.Enabled := False; | |
RadioButton4.Enabled := False; | |
end | |
else | |
begin | |
RadioButton1.Enabled := ChEnabled[0]; | |
RadioButton2.Enabled := ChEnabled[1]; | |
RadioButton3.Enabled := ChEnabled[2]; | |
RadioButton4.Enabled := ChEnabled[3]; | |
end; | |
end; | |
end; | |
function TGammaFrm.SelectedCh: integer; | |
begin | |
if RadioButton1.Checked then | |
Result := 0 | |
else if RadioButton2.Checked then | |
Result := 1 | |
else if RadioButton3.Checked then | |
Result := 2 | |
else if RadioButton4.Checked then | |
Result := 3 | |
else | |
Result := 0; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit hardconfig; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
StdCtrls, Buttons, Spin, ComCtrls, ExtCtrls, MPUnit, Mainfrm, Mask; | |
type | |
THardConfigDlg = class(TForm) | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
PageControl1: TPageControl; | |
TabSheet1: TTabSheet; | |
GroupBox1: TGroupBox; | |
GroupBox2: TGroupBox; | |
Label2: TLabel; | |
TabSheet2: TTabSheet; | |
TabSheet3: TTabSheet; | |
ComboBox1: TComboBox; | |
GroupBox3: TGroupBox; | |
RadioButton4: TRadioButton; | |
RadioButton5: TRadioButton; | |
RadioButton6: TRadioButton; | |
CheckBox2: TCheckBox; | |
CheckBox3: TCheckBox; | |
ComboBox3: TComboBox; | |
ComboBox4: TComboBox; | |
TabSheet4: TTabSheet; | |
GroupBox4: TGroupBox; | |
GroupBox5: TGroupBox; | |
RadioButton7: TRadioButton; | |
RadioButton8: TRadioButton; | |
RadioButton9: TRadioButton; | |
ComboBox5: TComboBox; | |
ComboBox6: TComboBox; | |
Label5: TLabel; | |
Label6: TLabel; | |
GroupBox7: TGroupBox; | |
Label7: TLabel; | |
Label8: TLabel; | |
RadioButton12: TRadioButton; | |
RadioButton13: TRadioButton; | |
RadioButton14: TRadioButton; | |
ComboBox7: TComboBox; | |
ComboBox8: TComboBox; | |
Label9: TLabel; | |
Label10: TLabel; | |
GroupBox8: TGroupBox; | |
Label11: TLabel; | |
ComboBox9: TComboBox; | |
GroupBox9: TGroupBox; | |
CheckBox5: TCheckBox; | |
Label4: TLabel; | |
ComboBox10: TComboBox; | |
CheckBox4: TCheckBox; | |
RadioButton3: TRadioButton; | |
RadioButton16: TRadioButton; | |
RadioButton17: TRadioButton; | |
Bevel2: TBevel; | |
Bevel4: TBevel; | |
Bevel5: TBevel; | |
Bevel6: TBevel; | |
Label14: TLabel; | |
Label15: TLabel; | |
Label16: TLabel; | |
Bevel7: TBevel; | |
Bevel8: TBevel; | |
RadioButton10: TRadioButton; | |
TabSheet5: TTabSheet; | |
Edit1: TEdit; | |
Label18: TLabel; | |
Label19: TLabel; | |
TabSheet6: TTabSheet; | |
RadioButton11: TRadioButton; | |
RadioButton15: TRadioButton; | |
Label23: TLabel; | |
Label24: TLabel; | |
Label25: TLabel; | |
Label26: TLabel; | |
Edit2: TEdit; | |
Edit3: TEdit; | |
Edit4: TEdit; | |
Label27: TLabel; | |
Edit5: TEdit; | |
Label28: TLabel; | |
Label29: TLabel; | |
Label30: TLabel; | |
Label31: TLabel; | |
Label32: TLabel; | |
Label33: TLabel; | |
Label34: TLabel; | |
Label35: TLabel; | |
Label36: TLabel; | |
Label37: TLabel; | |
Edit6: TEdit; | |
Edit7: TEdit; | |
Edit8: TEdit; | |
Edit9: TEdit; | |
CheckBox6: TCheckBox; | |
CheckBox7: TCheckBox; | |
CheckBox8: TCheckBox; | |
CheckBox9: TCheckBox; | |
CheckBox10: TCheckBox; | |
CheckBox11: TCheckBox; | |
CheckBox12: TCheckBox; | |
Label38: TLabel; | |
SpinEdit2: TSpinEdit; | |
Label39: TLabel; | |
SpinEdit3: TSpinEdit; | |
GroupBox6: TGroupBox; | |
Label40: TLabel; | |
ComboBox15: TComboBox; | |
CheckBox13: TCheckBox; | |
TabSheet7: TTabSheet; | |
GroupBox10: TGroupBox; | |
RadioButton20: TRadioButton; | |
RadioButton21: TRadioButton; | |
GroupBox11: TGroupBox; | |
Label41: TLabel; | |
ComboBox16: TComboBox; | |
RadioButton22: TRadioButton; | |
Label12: TLabel; | |
MaskEdit1: TMaskEdit; | |
Label17: TLabel; | |
Edit10: TEdit; | |
Bevel12: TBevel; | |
CheckBox14: TCheckBox; | |
GroupBox12: TGroupBox; | |
Label13: TLabel; | |
ComboBox11: TComboBox; | |
CheckBox15: TCheckBox; | |
GroupBox13: TGroupBox; | |
RadioButton1: TRadioButton; | |
Bevel1: TBevel; | |
Label1: TLabel; | |
RadioButton2: TRadioButton; | |
ComboBox2: TComboBox; | |
CheckBox1: TCheckBox; | |
Label3: TLabel; | |
SpinEdit1: TSpinEdit; | |
GroupBox14: TGroupBox; | |
CheckBox16: TCheckBox; | |
RadioButton23: TRadioButton; | |
Bevel3: TBevel; | |
RadioButton24: TRadioButton; | |
CheckBox17: TCheckBox; | |
Edit11: TEdit; | |
RadioButton18: TRadioButton; | |
RadioButton19: TRadioButton; | |
Edit12: TEdit; | |
procedure FormShow(Sender: TObject); | |
procedure CheckBox4Click(Sender: TObject); | |
procedure RadioButton2Click(Sender: TObject); | |
procedure RadioButton13Click(Sender: TObject); | |
procedure RadioButton8Click(Sender: TObject); | |
procedure BitBtn1Click(Sender: TObject); | |
procedure RadioButton4Click(Sender: TObject); | |
procedure CheckBox14Click(Sender: TObject); | |
procedure CheckBox13Click(Sender: TObject); | |
procedure CheckBox15Click(Sender: TObject); | |
private | |
{ Private declarations } | |
procedure OnXYControllerChosen; | |
public | |
{ Public declarations } | |
end; | |
var | |
HardConfigDlg: THardConfigDlg; | |
implementation | |
{$R *.DFM} | |
uses MPdevices; | |
function BaudToItemIndex(baud: integer): integer; | |
begin | |
case baud of | |
2400: Result := 0; | |
4800: Result := 1; | |
9600: Result := 2; | |
19200: Result := 3; | |
38400: Result := 4; | |
57600: Result := 5; | |
115200: Result := 6; | |
else Result := 2; | |
end; | |
end; | |
function ItemIndexToBaud(ii: integer): integer; | |
begin | |
case ii of | |
0: Result := 2400; | |
1: Result := 4800; | |
2: Result := 9600; | |
3: Result := 19200; | |
4: Result := 38400; | |
5: Result := 57600; | |
6: Result := 115200; | |
else Result := 9600; | |
end; | |
end; | |
procedure THardConfigDlg.OnXYControllerChosen; | |
begin | |
if RadioButton4.Checked then | |
{XY not installed} | |
begin | |
ComboBox3.Enabled := False; | |
ComboBox4.Enabled := False; | |
RadioButton3.Enabled := True; | |
RadioButton16.Enabled := True; | |
{we want to make sure that we don't have incompatible choices} | |
if RadioButton10.Checked then | |
begin | |
RadioButton10.Checked := False; | |
RadioButton3.Checked := True; | |
end; | |
RadioButton10.Enabled := False; | |
end | |
else if RadioButton5.Checked then | |
{NEAT 300} | |
begin | |
ComboBox3.Enabled := True; | |
ComboBox4.Enabled := True; | |
RadioButton3.Enabled := True; | |
RadioButton16.Enabled := True; | |
RadioButton10.Enabled := False; | |
{we want to make sure that we don't have incompatible choices} | |
if RadioButton10.Checked then | |
begin | |
RadioButton10.Checked := False; | |
RadioButton3.Checked := True; | |
end; | |
end | |
else if RadioButton17.Checked then | |
{MP285} | |
begin | |
ComboBox3.Enabled := True; | |
ComboBox4.Enabled := True; | |
RadioButton3.Enabled := False; | |
RadioButton16.Enabled := False; | |
RadioButton10.Checked := True; | |
end | |
else if RadioButton6.Checked then | |
{ESP300} | |
begin | |
ComboBox3.Enabled := True; | |
ComboBox4.Enabled := True; | |
RadioButton3.Enabled := False; | |
RadioButton16.Enabled := False; | |
RadioButton10.Checked := True; | |
end | |
else if RadioButton22.Checked then | |
begin {XPS controller} | |
ComboBox3.Enabled := False; | |
ComboBox4.Enabled := False; | |
RadioButton3.Enabled := False; | |
RadioButton16.Enabled := False; | |
RadioButton10.Checked := True; | |
end | |
else if RadioButton23.Checked then | |
begin {Galil controller} | |
ComboBox3.Enabled := True; | |
ComboBox4.Enabled := True; | |
RadioButton3.Enabled := False; | |
RadioButton16.Enabled := False; | |
RadioButton10.Checked := True; | |
end; | |
Edit10.Enabled := RadioButton22.Checked; | |
MaskEdit1.Enabled := RadioButton22.Checked; | |
Label38.Visible := RadioButton17.Checked; | |
SpinEdit2.Visible := RadioButton17.Checked; | |
end; | |
procedure THardConfigDlg.FormShow(Sender: TObject); | |
begin | |
ComboBox1.ItemIndex := multifunctionBoard.BoardIndex - 1; | |
CheckBox4.Checked := analogOutputBoard.Installed; | |
ComboBox9.ItemIndex := analogOutputBoard.BoardIndex - 1; | |
ComboBox9.Enabled := CheckBox4.Checked; | |
CheckBox13.Checked := opticsOutputBoard.Installed; | |
ComboBox15.ItemIndex := opticsOutputBoard.BoardIndex - 1; | |
ComboBox15.Enabled := CheckBox13.Checked; | |
CheckBox15.Checked := PhotonCountingBoard.Installed; | |
ComboBox11.ItemIndex := PhotonCountingBoard.BoardIndex - 1; | |
ComboBox11.Enabled := CheckBox15.Checked; | |
CheckBox5.Checked := multifunctionBoard.LogicLow; | |
ComboBox10.ItemIndex := multifunctionBoard.TTLTriggerPFILine; | |
RadioButton1.Checked := laserShutter.AnalogBoardControlsShutter; | |
RadioButton2.Checked := not RadioButton1.Checked; | |
CheckBox16.Checked := multifunctionBoard.bInvertPreamps; | |
ComboBox2.ItemIndex := laserShutter.multifunctionDIOIndex; | |
ComboBox2.Enabled := RadioButton2.Checked; | |
CheckBox1.Checked := laserShutter.CloseAfterSection; | |
SpinEdit1.Value := laserShutter.openDelay; | |
case xydeviceType of | |
XY_NOT_INSTALLED: RadioButton4.Checked := True; | |
XY_NEAT300: RadioButton5.Checked := True; | |
XY_MP285: RadioButton17.Checked := True; | |
XY_ESP300: RadioButton6.Checked := True; | |
XY_XPS: RadioButton22.Checked := True; | |
XY_GALIL: RadioButton23.Checked := True; | |
else RadioButton4.Checked := True; | |
end; | |
MaskEdit1.Text := XPS_IP; | |
Edit10.Text := XPS_GroupName; | |
ComboBox3.ItemIndex := XYTable.COMPort - 1; | |
ComboBox4.ItemIndex := BaudToItemIndex(XYTable.COMSpeed); | |
ComboBox3.Enabled := not RadioButton4.Checked; | |
ComboBox4.Enabled := not RadioButton4.Checked; | |
CheckBox3.Checked := XYTable.InvertX; | |
CheckBox2.Checked := XYTable.InvertY; | |
CheckBox6.Checked := ZStepper.InvertZ; | |
SpinEdit2.Value := micromanipulators[1].xyzReadDelay; | |
SpinEdit3.Value := micromanipulators[1].mmReadDelay; | |
OnXYControllerChosen; | |
{ ComboBox11.ItemIndex := ZStepper.COMPort - 1; | |
ComboBox12.ItemIndex := BaudToItemIndex(ZStepper.COMSpeed);} | |
case mmDeviceType[1] of | |
0: RadioButton12.Checked := True; | |
1: RadioButton13.Checked := True; | |
2: RadioButton14.Checked := True; | |
else RadioButton12.Checked := True; | |
end; | |
ComboBox7.ItemIndex := micromanipulators[1].COMPort - 1; | |
ComboBox8.ItemIndex := BaudToItemIndex(micromanipulators[1].COMSpeed); | |
ComboBox7.Enabled := RadioButton13.Checked; | |
ComboBox8.Enabled := RadioButton13.Checked; | |
case mmDeviceType[2] of | |
0: RadioButton7.Checked := True; | |
1: RadioButton8.Checked := True; | |
2: RadioButton9.Checked := True; | |
else RadioButton7.Checked := True; | |
end; | |
ComboBox5.ItemIndex := micromanipulators[2].COMPort - 1; | |
ComboBox6.ItemIndex := BaudToItemIndex(micromanipulators[2].COMSpeed); | |
ComboBox5.Enabled := RadioButton8.Checked; | |
ComboBox6.Enabled := RadioButton8.Checked; | |
CheckBox7.Checked := micromanipulators[1].InvertX; | |
CheckBox8.Checked := micromanipulators[1].InvertY; | |
CheckBox9.Checked := micromanipulators[1].InvertZ; | |
CheckBox10.Checked := micromanipulators[2].InvertX; | |
CheckBox11.Checked := micromanipulators[2].InvertY; | |
CheckBox12.Checked := micromanipulators[2].InvertZ; | |
CheckBox14.Checked := (Mainform.engine.MaxMirrorVoltage >= 5.0); | |
Edit1.Text := FloatToStr(Mainform.engine.MaxMirrorVoltage); | |
CheckBox17.Checked := Mainform.engine.OverrideMirrorFrequency; | |
case laserControlType of | |
LASER_NOT_INSTALLED: RadioButton11.Checked := True; | |
LASER_Kim_Zhang: RadioButton15.Checked := True; | |
LASER_MAI_TAI_0: RadioButton18.Checked := True; | |
LASER_MAI_TAI_1: RadioButton19.Checked := True; | |
end; | |
Edit2.Text := FloatToStr(laserControl.incA); | |
Edit3.Text := FloatToStr(laserControl.incB); | |
Edit4.Text := FloatToStr(laserControl.incC); | |
Edit5.Text := FloatToStr(laserControl.incD); | |
Edit6.Text := FloatToStr(laserControl.decA); | |
Edit7.Text := FloatToStr(laserControl.decB); | |
Edit8.Text := FloatToStr(laserControl.decC); | |
Edit9.Text := FloatToStr(laserControl.decD); | |
// ComboBox13.ItemIndex := laserControl.COMPort - 1; | |
// ComboBox14.ItemIndex := BaudToItemIndex(laserControl.COMSpeed); | |
if zPiezoType = ZPIEZO_NONE then | |
RadioButton20.Checked := True | |
else if zPiezoType = ZPIEZO_MIPOS100 then | |
RadioButton21.Checked := True | |
else | |
RadioButton24.Checked := True; | |
ComboBox16.ItemIndex := zPiezoOutChannel; | |
end; | |
procedure THardConfigDlg.CheckBox4Click(Sender: TObject); | |
begin | |
ComboBox9.Enabled := CheckBox4.Checked; | |
end; | |
procedure THardConfigDlg.RadioButton2Click(Sender: TObject); | |
begin | |
ComboBox2.Enabled := RadioButton2.Checked; | |
end; | |
procedure THardConfigDlg.RadioButton13Click(Sender: TObject); | |
begin | |
ComboBox7.Enabled := RadioButton13.Checked; | |
ComboBox8.Enabled := RadioButton13.Checked; | |
end; | |
procedure THardConfigDlg.RadioButton8Click(Sender: TObject); | |
begin | |
ComboBox5.Enabled := RadioButton8.Checked; | |
ComboBox6.Enabled := RadioButton8.Checked; | |
end; | |
procedure THardConfigDlg.BitBtn1Click(Sender: TObject); | |
var newVoltage, maxVoltage: double; I : double ; | |
begin | |
ModalResult := mrNone; | |
multifunctionBoard.BoardIndex := ComboBox1.ItemIndex + 1 ; | |
analogOutputBoard.Installed := CheckBox4.Checked; | |
analogOutputBoard.BoardIndex := ComboBox9.ItemIndex + 1; | |
opticsOutputBoard.Installed := CheckBox13.Checked; | |
opticsOutputBoard.BoardIndex := ComboBox15.ItemIndex + 1; | |
PhotonCountingBoard.Installed := CheckBox15.Checked; | |
PhotonCountingBoard.BoardIndex := ComboBox11.ItemIndex + 1; | |
multifunctionBoard.LogicLow := CheckBox5.Checked; | |
multifunctionBoard.TTLTriggerPFILine := ComboBox10.ItemIndex; | |
multifunctionBoard.bInvertPreamps := CheckBox16.Checked; | |
laserShutter.AnalogBoardControlsShutter := RadioButton1.Checked; | |
laserShutter.multifunctionDIOIndex := ComboBox2.ItemIndex; | |
laserShutter.CloseAfterSection := CheckBox1.Checked; | |
laserShutter.openDelay := SpinEdit1.Value; | |
if RadioButton11.Checked then | |
laserControlType := LASER_NOT_INSTALLED | |
else if RadioButton15.Checked then | |
laserControlType := LASER_Kim_Zhang | |
else if RadioButton18.Checked then | |
laserControlType := LASER_MAI_TAI_0 | |
else if RadioButton19.Checked then | |
laserControlType := LASER_MAI_TAI_1; | |
laserControl.incA := StrToFloat(Edit2.Text); | |
laserControl.incB := StrToFloat(Edit3.Text); | |
laserControl.incC := StrToFloat(Edit4.Text); | |
laserControl.incD := StrToFloat(Edit5.Text); | |
laserControl.decA := StrToFloat(Edit6.Text); | |
laserControl.decB := StrToFloat(Edit7.Text); | |
laserControl.decC := StrToFloat(Edit8.Text); | |
laserControl.decD := StrToFloat(Edit9.Text); | |
// end; | |
// procedure TAnalogStimFrm.SpeedButton1Click(Sender: TObject); | |
// for I := 0 to List.Count - 1 do | |
if RadioButton18.Checked then | |
analogOutputBoard.AnalogOut(1, StrToFloat(Edit11.Text)) | |
else if RadioButton19.Checked then | |
analogOutputBoard.AnalogOut(1, StrToFloat(Edit12.Text)/10); | |
// 10v to 100% | |
// | |
// laserControl.COMPort := ComboBox13.ItemIndex + 1; | |
// laserControl.COMSpeed := ItemIndexToBaud(ComboBox14.ItemIndex); | |
{X-Y-Z page} | |
XYTable.COMPort := ComboBox3.ItemIndex + 1; | |
XYTable.COMSpeed := ItemIndexToBaud(ComboBox4.ItemIndex); | |
XYTable.InvertX := CheckBox3.Checked; | |
XYTable.InvertY := CheckBox2.Checked; | |
ZStepper.InvertZ := CheckBox6.Checked; | |
if RadioButton4.Checked then xydeviceType := XY_NOT_INSTALLED | |
else if RadioButton5.Checked then xydeviceType := XY_NEAT300 | |
else if RadioButton17.Checked then | |
begin | |
xydeviceType := XY_MP285; | |
zStepperDeviceType := Z_MP285; | |
ZStepper.COMPort := XYTable.COMPort; | |
ZStepper.COMSpeed := XYTable.COMSpeed; | |
end | |
else if RadioButton6.Checked then | |
begin | |
xydeviceType := XY_ESP300; | |
zStepperDeviceType := Z_ESP300; | |
ZStepper.COMPort := XYTable.COMPort; | |
ZStepper.COMSpeed := XYTable.COMSpeed; | |
end | |
else if RadioButton22.Checked then {XPS} | |
begin | |
xydeviceType := XY_XPS; | |
zStepperDeviceType := Z_XPS; | |
ZStepper.COMPort := XYTable.COMPort; | |
ZStepper.COMSpeed := XYTable.COMSpeed; | |
end | |
else if RadioButton23.Checked then {GALIL} | |
begin | |
xydeviceType := XY_GALIL; | |
zStepperDeviceType := Z_GALIL; | |
ZStepper.COMPort := XYTable.COMPort; | |
ZStepper.COMSpeed := XYTable.COMSpeed; | |
end; | |
XPS_IP := MaskEdit1.Text; | |
XPS_GroupName := Edit10.Text; | |
micromanipulators[1].xyzReadDelay := SpinEdit2.Value; | |
micromanipulators[1].mmReadDelay := SpinEdit3.Value; | |
if RadioButton3.Checked then zStepperDeviceType := Z_NOT_INSTALLED | |
else if RadioButton16.Checked then zStepperDeviceType := Z_EARL; | |
{ else | |
begin | |
ZStepper.COMPort := ComboBox11.ItemIndex + 1; | |
ZStepper.COMSpeed := ItemIndexToBaud(ComboBox12.ItemIndex); | |
end;} | |
if RadioButton12.Checked then mmDeviceType[1] := 0 | |
else if RadioButton13.Checked then mmDeviceType[1] := 1 | |
else if RadioButton14.Checked then mmDeviceType[1] := 2; | |
micromanipulators[1].COMPort := ComboBox7.ItemIndex + 1; | |
micromanipulators[1].COMSpeed := ItemIndexToBaud(ComboBox8.ItemIndex); | |
if RadioButton7.Checked then mmDeviceType[2] := 0 | |
else if RadioButton8.Checked then mmDeviceType[2] := 1 | |
else if RadioButton9.Checked then mmDeviceType[2] := 2; | |
micromanipulators[2].COMPort := ComboBox5.ItemIndex + 1; | |
micromanipulators[2].COMSpeed := ItemIndexToBaud(ComboBox6.ItemIndex); | |
micromanipulators[1].InvertX := CheckBox7.Checked; | |
micromanipulators[1].InvertY := CheckBox8.Checked; | |
micromanipulators[1].InvertZ := CheckBox9.Checked; | |
micromanipulators[2].InvertX := CheckBox10.Checked; | |
micromanipulators[2].InvertY := CheckBox11.Checked; | |
micromanipulators[2].InvertZ := CheckBox12.Checked; | |
if RadioButton20.Checked then | |
zPiezoType := ZPIEZO_NONE | |
else if RadioButton21.Checked then | |
zPiezoType := ZPIEZO_MIPOS100 | |
else | |
zPiezoType := ZPIEZO_PIFOC725; | |
zPiezoOutChannel := ComboBox16.ItemIndex; | |
ComboBox16.ItemIndex := zPiezoOutChannel; | |
if CheckBox14.Checked then maxVoltage := 10.0 else maxVoltage := 5.0; | |
newVoltage := StrToFloat(Edit1.Text); | |
if (newVoltage > 0) and (newVoltage <= maxVoltage) then | |
begin | |
if Mainform.engine.MaxMirrorVoltage <> newVoltage then | |
MessageDlg('You must restart MPScan to apply the new Maximal Mirror Command Voltage value.', mtInformation, [mbOK], 0); | |
Mainform.engine.MaxMirrorVoltage := newVoltage; | |
ModalResult := mrOK; | |
end | |
else | |
MessageDlg('Invalid value for the Maximal Mirror Command Voltage.', mtError, [mbOK], 0); | |
if CheckBox17.Checked then | |
begin | |
if not Mainform.engine.OverrideMirrorFrequency then | |
begin | |
if MessageDlg('Are you sure you want to override mirror frequency limit?', mtInformation, [mbYes, mbNo], 0) = mrYes then | |
Mainform.engine.OverrideMirrorFrequency := CheckBox17.Checked; | |
end; | |
end | |
else | |
Mainform.engine.OverrideMirrorFrequency := CheckBox17.Checked; | |
end; | |
procedure THardConfigDlg.RadioButton4Click(Sender: TObject); | |
begin | |
OnXYControllerChosen; | |
end; | |
procedure THardConfigDlg.CheckBox14Click(Sender: TObject); | |
begin | |
if CheckBox14.Checked then | |
MessageDlg('You can now enter a maximal voltage up to 10 V.', mtWarning, [mbOK], 0) | |
else | |
MessageDlg('Maximal voltage is restricted to 5 V.', mtInformation, [mbOK], 0); | |
end; | |
procedure THardConfigDlg.CheckBox13Click(Sender: TObject); | |
begin | |
ComboBox15.Enabled := CheckBox13.Checked; | |
end; | |
procedure THardConfigDlg.CheckBox15Click(Sender: TObject); | |
begin | |
ComboBox11.Enabled := CheckBox15.Checked; | |
end; | |
end. | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit Horzbaru; | |
interface | |
uses | |
Messages, Windows, Classes, Graphics, Controls, Menus, ExtCtrls; | |
type | |
{integer = integer;} | |
TDrawTickEvent = procedure(Sender: TObject) of object; | |
TCustomTrack = class(TCustomControl) | |
private | |
fOwnerDrawTicks: TDrawTickEvent; | |
protected | |
procedure DrawTicks; | |
public | |
procedure DrawMajorTicks(pos: integer); virtual; abstract; | |
procedure DrawMinorTicks(pos: integer); virtual; abstract; | |
{callback to draw ticks} | |
property OwnerDrawTicks: TDrawTickEvent write fOwnerDrawTicks; | |
end; | |
THorzTrackBar = class(TCustomTrack) | |
private | |
fCursor: TObject; | |
fMax, fMin, fPosition, fPageSize: integer; | |
fScreenPos: integer; | |
fSliding: boolean; | |
fCursorRect: TRect; | |
{in screen coordinates: | |
fMajorTickInterval: interval between major ticks > 0 | |
fFirstMajorTickPos: position of the lowest first tick mark > 0 | |
cMinorTickCount: number of minor ticks between each tick mark > 0} | |
{fMajorTickInterval, fFirstMajorTickPos, fMinorTickCount: integer;} | |
fDitherBmp, fCursorBmp, fMaskBmp, fBackgroundBmp: TBitmap; | |
fOnChange: TNotifyEvent; | |
function CursorToScreen( Value: integer): integer; | |
function ScreenToCursor( Value: integer): integer; | |
function LimitPosition( Value: integer): integer; {clips value to the control} | |
procedure SetMax( Value : integer ); | |
procedure SetMin( Value : integer ); | |
procedure SetPosition( Value : integer ); | |
function GetScreenPosition: integer; | |
procedure SetScreenPosition( Value : integer ); | |
procedure LoadThumbBitmaps; | |
procedure UpdateDitherBitmap; | |
procedure DrawTrack; | |
procedure DrawCursor; | |
procedure WMGetDlgCode( var Msg : TWMGetDlgCode ); message wm_GetDlgCode; | |
procedure CMEnabledChanged( var Msg : TMessage ); message cm_EnabledChanged; | |
protected | |
procedure Paint; override; | |
procedure Change; dynamic; | |
procedure DoEnter; override; | |
procedure DoExit; override; | |
procedure KeyDown( var Key : Word; Shift : TShiftState ); override; | |
procedure MouseDown( Button : TMouseButton; Shift : TShiftState; X, Y : Integer ); override; | |
procedure MouseMove( Shift : TShiftState; X, Y : Integer ); override; | |
procedure MouseUp( Button : TMouseButton; Shift : TShiftState; X, Y : Integer ); override; | |
public | |
constructor Create( AOwner : TComponent ); override; | |
constructor CreateInCursor( AOwner: TComponent; theCursor: TObject); | |
destructor Destroy; override; | |
function CursorVisible: boolean; | |
procedure SetParams(theMax, theMin, thePos: integer); | |
procedure DrawMajorTicks(pos: integer); override; | |
procedure DrawMinorTicks(pos: integer); override; | |
published | |
property ScreenPos: integer read GetScreenPosition write SetScreenPosition; | |
property Max : integer read fMax write SetMax default 999; | |
property Min : integer read fMin write SetMin default 0; | |
property PageSize : integer read fPageSize write fPageSize default 50; | |
property Position : integer read fPosition write SetPosition; | |
property OnChange : TNotifyEvent read fOnChange write fOnChange; | |
{ Inherited Properties & Events } | |
property Color; | |
property DragCursor; | |
property DragMode; | |
property Enabled; | |
property HelpContext; | |
property Hint; | |
property ParentShowHint; | |
property PopupMenu; | |
property ShowHint; | |
property TabOrder; | |
property TabStop default True; | |
property Visible; | |
property OnClick; | |
property OnDragDrop; | |
property OnDragOver; | |
property OnEndDrag; | |
property OnEnter; | |
property OnExit; | |
property OnKeyDown; | |
property OnKeyPress; | |
property OnKeyUp; | |
property OnMouseDown; | |
property OnMouseMove; | |
property OnMouseUp; | |
end; | |
procedure Register; | |
implementation | |
uses SysUtils {, cursorsu, viewdata}; | |
{$R CURSORS} | |
procedure TCustomTrack.DrawTicks; | |
begin | |
{calls the owner to draw ticks} | |
if Assigned(fOwnerDrawTicks) then fOwnerDrawTicks(Self); | |
end; | |
procedure THorzTrackBar.DrawMajorTicks(pos: integer); | |
begin | |
with Canvas do | |
begin | |
Pen.Color := clBlack; | |
Pen.Width := 1; | |
MoveTo(pos, 8); | |
LineTo(pos, 17); | |
end; | |
end; | |
procedure THorzTrackBar.DrawMinorTicks(pos: integer); | |
begin | |
with Canvas do | |
begin | |
Pen.Color := clBlack; | |
Pen.Width := 1; | |
MoveTo(pos, 12); | |
LineTo(pos, 17); | |
end; | |
end; | |
function THorzTrackBar.CursorToScreen( Value: integer): integer; | |
begin | |
Result := Muldiv(Value - fMin, ClientWidth - 1, fMax - fMin); | |
if Result < 0 then Result := 0; | |
if Result >= ClientWidth then Result := ClientWidth - 1; | |
end; | |
function THorzTrackBar.ScreenToCursor( Value: integer): integer; | |
begin | |
Result := fMin + Muldiv(Value, fMax - fMin, ClientWidth - 1); | |
end; | |
function THorzTrackBar.LimitPosition( Value: integer): integer; | |
begin | |
Result :=Value; | |
if Result > fMax then Result := fMax; | |
if Result < fMin then Result := fMin; | |
end; | |
procedure THorzTrackBar.SetMax( Value : integer ); | |
begin | |
if value <> fMax then | |
begin | |
fMax := Value; | |
if fPosition > fMax then screenPos := CursorToScreen(fMax); | |
fPageSize := (fMax - fMin) div 20; | |
Invalidate; | |
end; | |
end; | |
procedure THorzTrackBar.SetMin( Value : integer ); | |
begin | |
if value <> fMin then | |
begin | |
fMin := Value; | |
if fPosition < fMin then screenPos := CursorToScreen(fMin); | |
fPageSize := (fMax - fMin) div 20; | |
Invalidate; | |
end; | |
end; | |
procedure THorzTrackBar.SetPosition( Value : integer ); | |
begin | |
if value <> fPosition then | |
begin | |
fPosition := Value; | |
if csDesigning in ComponentState then | |
Invalidate | |
else | |
begin | |
{ Erase old thumb image by drawing background bitmap } | |
Canvas.Draw( fCursorRect.Left, fCursorRect.Top, FBackgroundBmp ); | |
DrawCursor; { Draw thumb at new location } | |
Change; { Trigger Change event } | |
end; | |
end; | |
end; | |
function THorzTrackBar.GetScreenPosition; | |
begin | |
Result := CursorToScreen(fPosition); | |
end; | |
procedure THorzTrackBar.SetScreenPosition( Value : Integer ); | |
begin | |
if Value < 0 then Value := 0; | |
if Value >= ClientWidth then Value := ClientWidth - 1; | |
fPosition := ScreenToCursor(Value); | |
Invalidate; | |
end; | |
procedure THorzTrackBar.LoadThumbBitmaps; | |
const | |
hCursor: PChar = 'HCURSOR'; | |
hMask: PChar = 'HMASK'; | |
begin | |
fCursorBmp.Handle := LoadBitmap(hInstance, hCursor); | |
fMaskBmp.Handle := LoadBitmap(hInstance, hMask); | |
end; | |
procedure THorzTrackBar.UpdateDitherBitmap; | |
var | |
i, j : integer; | |
begin | |
with fDitherBmp.Canvas do | |
begin | |
Brush.Color := clWhite; | |
FillRect( Rect( 0, 0, fDitherBmp.Width, fDitherBmp.Height ) ); | |
for i := 0 to 7 do | |
for j := 0 to 7 do | |
if ( i + j ) mod 2 <> 0 then | |
Pixels[ i, j ] := clSilver; | |
end; | |
end; | |
procedure THorzTrackBar.DrawTrack; | |
begin | |
Canvas.Brush.Color := clWhite; | |
if not Enabled then | |
Canvas.Brush.Bitmap := fDitherBmp; | |
Canvas.FillRect(ClientRect); | |
end; | |
procedure THorzTrackBar.DrawCursor; | |
var | |
workBmp : TBitmap; | |
workRct : TRect; | |
begin | |
fScreenPos := CursorToScreen(fPosition); | |
fCursorRect := Rect(fScreenPos - 7, 1, fScreenPos + 8, 16); | |
fBackgroundBmp.Width := 15; | |
fBackgroundBmp.Height := 15; | |
fBackgroundBmp.Canvas.CopyRect( Rect(0, 0, fCursorBmp.Width, fCursorBmp.Height), | |
Canvas, fCursorRect ); | |
workBmp := TBitmap.Create; | |
try | |
workBmp.Height := fCursorBmp.Height; | |
workBmp.Width := fCursorBmp.Width; | |
workRct := Rect( 0, 0, fCursorBmp.Width, fCursorBmp.Height); | |
workBmp.Canvas.CopyMode := cmSrcCopy; | |
workBmp.Canvas.CopyRect( WorkRct, fBackgroundBmp.Canvas, workRct ); | |
workBmp.Canvas.CopyMode := cmSrcAnd; | |
workBmp.Canvas.CopyRect( WorkRct, fMaskBmp.Canvas, WorkRct ); | |
workBmp.Canvas.CopyMode := cmSrcPaint; | |
WorkBmp.Canvas.CopyRect( WorkRct, fCursorBmp.Canvas, WorkRct ); | |
if not Enabled then | |
begin | |
WorkBmp.Canvas.Brush.Bitmap := fDitherBmp; | |
WorkBmp.Canvas.FloodFill( WorkRct.Right - 3, WorkRct.Bottom - 3, | |
clSilver, fsSurface ); | |
end; | |
Canvas.CopyRect( fCursorRect, WorkBmp.Canvas, WorkRct ); | |
finally | |
workBmp.Free; | |
end; | |
end; | |
procedure THorzTrackBar.WMGetDlgCode( var Msg : TWMGetDlgCode ); | |
begin | |
inherited; | |
Msg.Result := dlgc_WantArrows; | |
end; | |
procedure THorzTrackBar.CMEnabledChanged( var Msg : TMessage ); | |
begin | |
inherited; | |
Invalidate; | |
end; | |
procedure THorzTrackBar.Paint; | |
begin | |
with Canvas do | |
begin | |
DrawTrack; | |
DrawTicks; | |
DrawCursor; | |
end; | |
end; | |
procedure THorzTrackBar.Change; | |
begin | |
if Assigned( FOnChange ) then FOnChange( Self ); | |
end; | |
procedure THorzTrackBar.DoEnter; | |
begin | |
inherited DoEnter; | |
Refresh; | |
end; | |
procedure THorzTrackBar.DoExit; | |
begin | |
inherited DoExit; | |
Refresh; | |
end; | |
procedure THorzTrackBar.KeyDown( var Key : Word; Shift : TShiftState ); | |
begin | |
inherited KeyDown( Key, Shift ); | |
case Key of | |
vk_Prior: | |
Position := LimitPosition(fPosition + fPageSize); | |
vk_Next: | |
Position := LimitPosition(fPosition - FPageSize); | |
vk_End: | |
Position := fMin; | |
vk_Home: | |
Position := fMax; | |
vk_Left: | |
if fPosition > fMin then Position := LimitPosition(fPosition - 1); | |
vk_Up: | |
if fPosition < fMax then Position := LimitPosition(fPosition + 1); | |
vk_Right: | |
if fPosition < fMax then Position := LimitPosition(fPosition + 1); | |
vk_Down: | |
if fPosition > fMin then Position := LimitPosition(fPosition - 1); | |
end; | |
end; | |
procedure THorzTrackBar.MouseDown( Button : TMouseButton; Shift : TShiftState; X, Y : Integer ); | |
begin | |
inherited MouseDown( Button, Shift, X, Y ); | |
SetFocus; | |
if ( Button = mbLeft ) and PtInRect( fCursorRect, Point( X, Y ) ) then | |
fSliding := True | |
else | |
begin | |
if ScreenToCursor(X) < fPosition then | |
Position := LimitPosition(fPosition - fPageSize) | |
else | |
Position := LimitPosition(fPosition + fPageSize); | |
end; | |
end; | |
procedure THorzTrackBar.MouseMove( Shift : TShiftState; X, Y : Integer ); | |
var { h : Integer;} | |
p: integer; | |
begin | |
inherited MouseMove( Shift, X, Y ); | |
if PtInRect( FCursorRect, Point( X, Y ) ) then | |
Cursor := crSizeWE | |
else | |
Cursor := crDefault; | |
if fSliding then | |
begin | |
{ h := ClientWidth - 7;} | |
p:= fMin + Muldiv(X, fMax - fMin, ClientWidth - 1); | |
if p > fMax then p := fMax; | |
if p < fMin then p := fMin; | |
Position := p; | |
end; | |
end; | |
procedure THorzTrackBar.MouseUp( Button : TMouseButton; Shift : TShiftState; X, Y : Integer ); | |
begin | |
inherited MouseUp( Button, Shift, X, Y ); | |
if ( Button = mbLeft ) then fSliding := False; | |
end; | |
constructor THorzTrackBar.Create( AOwner : TComponent ); | |
begin | |
inherited Create( AOwner ); | |
Width := 200; | |
Height := 17; | |
fMin := 0; | |
fMax := 65536; | |
fPosition := 0; | |
fPageSize := 65536 div 20; | |
fSliding := False; | |
fCursorBmp := TBitmap.Create; | |
fCursorBmp.Width := 16; | |
fCursorBmp.Height := 16; | |
fMaskBmp := TBitmap.Create; | |
fBackgroundBmp := TBitmap.Create; | |
fDitherBmp := TBitmap.Create; | |
fDitherBmp.Width := 8; | |
fDitherBmp.Height := 8; | |
UpdateDitherBitmap; | |
LoadThumbBitmaps; | |
end; | |
constructor THorzTrackBar.CreateInCursor( AOwner: TComponent; theCursor: TObject); | |
begin | |
Create(AOwner); | |
fCursor := theCursor; | |
end; | |
destructor THorzTrackBar.Destroy; | |
begin | |
FreeAndNil(fCursorBmp); | |
FreeAndNil(fMaskBmp); | |
FreeAndNil(fBackgroundBmp); | |
FreeAndNil(fDitherBmp); | |
inherited Destroy; | |
end; | |
function THorzTrackBar.CursorVisible: boolean; | |
begin | |
if (fPosition <= fMax) and (fPosition >= fMin) then Result := True else Result := False; | |
end; | |
procedure THorzTrackBar.SetParams(theMax, theMin, thePos: integer); | |
begin | |
fMax := theMax; | |
fMin := theMin; | |
fPosition := thePos; | |
fPageSize := (fMax - fMin) div 20; | |
end; | |
procedure Register; | |
begin | |
RegisterComponents( 'Samples', [THorzTrackBar] ); | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit lutdlgu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
Buttons, ExtCtrls, StdCtrls, ComCtrls, Spin, Vieweru, MPViewu; | |
type | |
TLUTDlg = class(TForm) | |
TabControl1: TTabControl; | |
GroupBox1: TGroupBox; | |
CheckBox1: TCheckBox; | |
CheckBox2: TCheckBox; | |
CheckBox3: TCheckBox; | |
PaintBox1: TPaintBox; | |
GroupBox2: TGroupBox; | |
SpeedButton1: TSpeedButton; | |
PaintBox2: TPaintBox; | |
GroupBox3: TGroupBox; | |
SpeedButton2: TSpeedButton; | |
PaintBox3: TPaintBox; | |
GroupBox4: TGroupBox; | |
SpeedButton3: TSpeedButton; | |
PaintBox4: TPaintBox; | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
SpinEdit1: TSpinEdit; | |
Label1: TLabel; | |
ColorDialog1: TColorDialog; | |
Label2: TLabel; | |
SpinEdit2: TSpinEdit; | |
procedure CheckBox1Click(Sender: TObject); | |
procedure SpeedButton1Click(Sender: TObject); | |
procedure BitBtn1Click(Sender: TObject); | |
procedure TabControl1Change(Sender: TObject); | |
procedure SpeedButton2Click(Sender: TObject); | |
procedure SpeedButton3Click(Sender: TObject); | |
procedure PaintBox1Paint(Sender: TObject); | |
procedure PaintBox2Paint(Sender: TObject); | |
procedure PaintBox4Paint(Sender: TObject); | |
procedure FormShow(Sender: TObject); | |
procedure PaintBox3Paint(Sender: TObject); | |
procedure SpinEdit2Change(Sender: TObject); | |
procedure TabControl1Changing(Sender: TObject; | |
var AllowChange: Boolean); | |
private | |
{ Private declarations } | |
bDontChange: boolean; | |
public | |
{ Public declarations } | |
dlgBaseColors: TBaseColorsArray; | |
dlgnegativeColors, | |
dlgmidRangeColors, | |
dlgmaxColors: TRangeColorsArray; | |
dlgMaxPixels: TMaxPixelsArray; | |
viewer: TViewerFrm; | |
end; | |
var | |
LUTDlg: TLUTDlg; | |
implementation | |
{$R *.DFM} | |
uses Mainfrm; | |
procedure TLUTDlg.CheckBox1Click(Sender: TObject); | |
var r,g,b: Byte; | |
begin | |
r := 0; g := 0; b := 0; | |
if not bDontChange then | |
begin | |
dlgBaseColors[TabControl1.TabIndex, 0] := CheckBox1.Checked; | |
dlgBaseColors[TabControl1.TabIndex, 1] := CheckBox2.Checked; | |
dlgBaseColors[TabControl1.TabIndex, 2] := CheckBox3.Checked; | |
end; | |
if SpinEdit1.Value >= SpinEdit2.Value then | |
PaintBox1.Color := RGB(dlgmaxColors[TabControl1.TabIndex].rgbtRed, | |
dlgmaxColors[TabControl1.TabIndex].rgbtGreen, | |
dlgmaxColors[TabControl1.TabIndex].rgbtBlue) | |
else | |
begin | |
if CheckBox1.Checked then r := Muldiv($FF, SpinEdit1.Value, SpinEdit2.Value - 1); | |
if CheckBox2.Checked then g := Muldiv($FF, SpinEdit1.Value, SpinEdit2.Value - 1); | |
if CheckBox3.Checked then b := Muldiv($FF, SpinEdit1.Value, SpinEdit2.Value - 1); | |
PaintBox1.Color := RGB(r, g, b); | |
end; | |
PaintBox1.Invalidate; | |
end; | |
procedure TLUTDlg.SpeedButton1Click(Sender: TObject); | |
begin | |
ColorDialog1.Color := RGB( dlgnegativeColors[TabControl1.TabIndex].rgbtRed, | |
dlgnegativeColors[TabControl1.TabIndex].rgbtGreen, | |
dlgnegativeColors[TabControl1.TabIndex].rgbtBlue); | |
if ColorDialog1.Execute then | |
begin | |
{TRGBQuad has order of R, G, B reversed} | |
dlgnegativeColors[TabControl1.TabIndex].rgbtRed := TRGBQuad(ColorDialog1.Color).rgbBlue; | |
dlgnegativeColors[TabControl1.TabIndex].rgbtGreen := TRGBQuad(ColorDialog1.Color).rgbGreen; | |
dlgnegativeColors[TabControl1.TabIndex].rgbtBlue := TRGBQuad(ColorDialog1.Color).rgbRed; | |
PaintBox2.Color := ColorDialog1.Color; | |
PaintBox2.Invalidate; | |
end; | |
end; | |
procedure TLUTDlg.BitBtn1Click(Sender: TObject); | |
var i: integer; | |
begin | |
if (dlgBaseColors[0, 0] or dlgBaseColors[0, 1] or dlgBaseColors[0, 2] = False) or | |
(dlgBaseColors[1, 0] or dlgBaseColors[1, 1] or dlgBaseColors[1, 2] = False) or | |
(dlgBaseColors[2, 0] or dlgBaseColors[2, 1] or dlgBaseColors[2, 2] = False) or | |
(dlgBaseColors[3, 0] or dlgBaseColors[3, 1] or dlgBaseColors[3, 2] = False) then | |
begin | |
MessageDlg('Base colors cannot be black.', mtError, [mbOK], 0); | |
ModalResult := mrNone; | |
end | |
else | |
with Viewer.mpFile do | |
begin | |
BaseColors := dlgBaseColors; | |
negativeColors := dlgnegativeColors; | |
midRangeColors := dlgmidRangeColors; | |
maxColors := dlgmaxColors; | |
for i := 0 to MAX_CH - 1 do | |
if dlgMaxPixels[i] > 2047 then dlgMaxPixels[i] := 2047 | |
else if dlgMaxPixels[i] < 50 then dlgMaxPixels[i] := 50; | |
maxPixels := dlgMaxPixels; | |
end; | |
end; | |
procedure TLUTDlg.TabControl1Change(Sender: TObject); | |
begin | |
bDontChange := True; | |
CheckBox1.Checked := dlgBaseColors[TabControl1.TabIndex, 0]; | |
CheckBox2.Checked := dlgBaseColors[TabControl1.TabIndex, 1]; | |
CheckBox3.Checked := dlgBaseColors[TabControl1.TabIndex, 2]; | |
PaintBox2.Color := RGB( dlgnegativeColors[TabControl1.TabIndex].rgbtRed, | |
dlgnegativeColors[TabControl1.TabIndex].rgbtGreen, | |
dlgnegativeColors[TabControl1.TabIndex].rgbtBlue); | |
PaintBox3.Color := RGB( dlgmidRangeColors[TabControl1.TabIndex].rgbtRed, | |
dlgmidRangeColors[TabControl1.TabIndex].rgbtGreen, | |
dlgmidRangeColors[TabControl1.TabIndex].rgbtBlue); | |
PaintBox4.Color := RGB( dlgmaxColors[TabControl1.TabIndex].rgbtRed, | |
dlgmaxColors[TabControl1.TabIndex].rgbtGreen, | |
dlgmaxColors[TabControl1.TabIndex].rgbtBlue); | |
SpinEdit2.Value := dlgMaxPixels[TabControl1.TabIndex]; | |
CheckBox1Click(nil); | |
PaintBox1.Invalidate; | |
PaintBox2.Invalidate; | |
PaintBox3.Invalidate; | |
PaintBox4.Invalidate; | |
bDontChange := False; | |
end; | |
procedure TLUTDlg.SpeedButton2Click(Sender: TObject); | |
begin | |
ColorDialog1.Color := RGB( dlgmidRangeColors[TabControl1.TabIndex].rgbtRed, | |
dlgmidRangeColors[TabControl1.TabIndex].rgbtGreen, | |
dlgmidRangeColors[TabControl1.TabIndex].rgbtBlue); | |
if ColorDialog1.Execute then | |
begin | |
dlgmidRangeColors[TabControl1.TabIndex].rgbtRed := TRGBQuad(ColorDialog1.Color).rgbBlue; | |
dlgmidRangeColors[TabControl1.TabIndex].rgbtGreen := TRGBQuad(ColorDialog1.Color).rgbGreen; | |
dlgmidRangeColors[TabControl1.TabIndex].rgbtBlue := TRGBQuad(ColorDialog1.Color).rgbRed; | |
PaintBox3.Color := ColorDialog1.Color; | |
PaintBox3.Invalidate; | |
end; | |
end; | |
procedure TLUTDlg.SpeedButton3Click(Sender: TObject); | |
begin | |
ColorDialog1.Color := RGB( dlgmaxColors[TabControl1.TabIndex].rgbtRed, | |
dlgmaxColors[TabControl1.TabIndex].rgbtGreen, | |
dlgmaxColors[TabControl1.TabIndex].rgbtBlue); | |
if ColorDialog1.Execute then | |
begin | |
dlgmaxColors[TabControl1.TabIndex].rgbtRed := TRGBQuad(ColorDialog1.Color).rgbBlue; | |
dlgmaxColors[TabControl1.TabIndex].rgbtGreen := TRGBQuad(ColorDialog1.Color).rgbGreen; | |
dlgmaxColors[TabControl1.TabIndex].rgbtBlue := TRGBQuad(ColorDialog1.Color).rgbRed; | |
PaintBox4.Color := ColorDialog1.Color; | |
PaintBox4.Invalidate; | |
end; | |
end; | |
procedure TLUTDlg.PaintBox1Paint(Sender: TObject); | |
begin | |
with PaintBox1, PaintBox1.Canvas do | |
begin | |
Brush.Color := Color; | |
FillRect(ClientRect); | |
end; | |
end; | |
procedure TLUTDlg.PaintBox2Paint(Sender: TObject); | |
begin | |
with PaintBox2, PaintBox2.Canvas do | |
begin | |
Brush.Color := Color; | |
FillRect(ClientRect); | |
end; | |
end; | |
procedure TLUTDlg.PaintBox4Paint(Sender: TObject); | |
begin | |
with PaintBox4, PaintBox4.Canvas do | |
begin | |
Brush.Color := Color; | |
FillRect(ClientRect); | |
end; | |
end; | |
procedure TLUTDlg.FormShow(Sender: TObject); | |
begin | |
TabControl1.TabIndex := Viewer.MPFile.DefaultVideoChannel; | |
TabControl1Change(nil); | |
CheckBox1Click(nil); | |
end; | |
procedure TLUTDlg.PaintBox3Paint(Sender: TObject); | |
begin | |
with PaintBox3, PaintBox3.Canvas do | |
begin | |
Brush.Color := Color; | |
FillRect(ClientRect); | |
end; | |
end; | |
procedure TLUTDlg.SpinEdit2Change(Sender: TObject); | |
begin | |
dlgMaxPixels[TabControl1.TabIndex] := SpinEdit2.Value; | |
CheckBox1Click(nil); | |
end; | |
procedure TLUTDlg.TabControl1Changing(Sender: TObject; | |
var AllowChange: Boolean); | |
begin | |
dlgBaseColors[TabControl1.TabIndex, 0] := CheckBox1.Checked; | |
dlgBaseColors[TabControl1.TabIndex, 1] := CheckBox2.Checked; | |
dlgBaseColors[TabControl1.TabIndex, 2] := CheckBox3.Checked; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit mainfrm; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
Menus, ImgList, ToolWin, ComCtrls, mpviewu, Buttons, ExtCtrls, mpfileu, | |
COMObj, ActiveX, ShellAPI, ROIFrmu; | |
const | |
WM_POSTSHOWMSG = WM_APP + 400; | |
type | |
TMainform = class(TForm) | |
MainMenu1: TMainMenu; | |
File1: TMenuItem; | |
NewFile1: TMenuItem; | |
OpenFile1: TMenuItem; | |
SaveFileAs1: TMenuItem; | |
N1: TMenuItem; | |
Close1: TMenuItem; | |
N2: TMenuItem; | |
Exit1: TMenuItem; | |
Help1: TMenuItem; | |
About1: TMenuItem; | |
FileInformation1: TMenuItem; | |
N5: TMenuItem; | |
OpenDialog1: TOpenDialog; | |
SaveDialog1: TSaveDialog; | |
Panel1: TPanel; | |
SpeedButton1: TSpeedButton; | |
Settings1: TMenuItem; | |
Options1: TMenuItem; | |
StopMatlab1: TMenuItem; | |
SpeedButton2: TSpeedButton; | |
Window1: TMenuItem; | |
N3: TMenuItem; | |
ArrangeAll1: TMenuItem; | |
Cascade1: TMenuItem; | |
Tile1: TMenuItem; | |
FileAs1: TMenuItem; | |
AnalogDataAs1: TMenuItem; | |
ROIDataAs1: TMenuItem; | |
Scripting1: TMenuItem; | |
ShowScriptingEnvironment1: TMenuItem; | |
Panel2: TPanel; | |
procedure FormCreate(Sender: TObject); | |
procedure FormDestroy(Sender: TObject); | |
procedure OpenFile1Click(Sender: TObject); | |
procedure NewFile1Click(Sender: TObject); | |
procedure SaveFileAs1Click(Sender: TObject); | |
procedure FormClose(Sender: TObject; var Action: TCloseAction); | |
procedure FormShow(Sender: TObject); | |
procedure About1Click(Sender: TObject); | |
procedure Options1Click(Sender: TObject); | |
procedure StopMatlab1Click(Sender: TObject); | |
procedure FileInformation1Click(Sender: TObject); | |
procedure Close1Click(Sender: TObject); | |
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); | |
procedure Exit1Click(Sender: TObject); | |
procedure Tile1Click(Sender: TObject); | |
procedure Cascade1Click(Sender: TObject); | |
procedure ArrangeAll1Click(Sender: TObject); | |
procedure AnalogDataAs1Click(Sender: TObject); | |
procedure ROIDataAs1Click(Sender: TObject); | |
private | |
{ Private declarations } | |
procedure InitializeColorTables; | |
function GetActiveFile: TObject; {returns the file associated with the MDI window} | |
public | |
{ Public declarations } | |
{24-bit gray scale or false color table} | |
grayScaleTable, falseColorTable: array[0..MAX_FALSE_COLORS-1] of TRGBTriple; | |
bAppClosing, | |
bBinaryOp, | |
bLocalMatlabServer: boolean; | |
remoteMatlabServer: string; | |
matlab : OleVariant; | |
fileList: TFileList; | |
procedure WMDROPFILES(var Message: TMessage); message WM_DROPFILES; | |
procedure WMPOSTSHOWMSG(var Message: TMessage); message WM_POSTSHOWMSG; | |
property activeFile: TObject read GetActiveFile; | |
end; | |
var | |
Mainform: TMainform; | |
implementation | |
{$R *.DFM} | |
uses RegStr, Registry, Optdlgu, Fileinfodlgu, vieweru, aboutdlgu, mconsolefrm, Math, | |
analogu, vfw, {Variants,} cpyanaldlgu, FileCtrl; | |
const | |
sSection = 'Application Settings'; | |
sEntry = 'Position'; | |
sDirectory = 'Data Directory'; | |
sbLocalServer = 'Local Server'; | |
sRemoteServerLocation = 'Remote Server'; | |
sAppName = 'MPView'; | |
{******************************** Private methods *****************************} | |
procedure TMainform.InitializeColorTables; | |
var i, n, g, r, b, offset: integer; | |
u: array of integer; | |
J: array[1..MAX_FALSE_COLORS,1..3] of integer; | |
begin | |
{gray scales} | |
for i := 0 to 2047 do | |
begin | |
grayScaleTable[i].rgbtBlue := i div 8; | |
grayScaleTable[i].rgbtGreen := i div 8; | |
grayScaleTable[i].rgbtRed := i div 8; | |
end; | |
{false colors} | |
n := ceil(MAX_FALSE_COLORS / 4); | |
SetLength(u, 3 * n - 1); | |
for i := 0 to n-1 do u[i] := Muldiv(255,i + 1,n); | |
for i := n to 2*n - 2 do u[i] := 255; | |
for i := 2*n - 1 to 3*n - 2 do u[i] := Muldiv(255, 3*n - i + 1, n); | |
if MAX_FALSE_COLORS mod 4 = 1 then g := -1 else g := 0; | |
g := g + ceil(n/2) + 1; {g[1..3 * n - 1]} | |
r := g + n; | |
b := g - n; | |
if b < 1 then offset := -b + 1 else offset := 0; | |
for i := 1 to MAX_FALSE_COLORS do | |
begin | |
J[i, 1] := 0; | |
J[i, 2] := 0; | |
J[i, 3] := 0; | |
end; | |
for i := 1 to MAX_FALSE_COLORS do | |
begin | |
if (i + r <= MAX_FALSE_COLORS) and (i < 3*n) then J[i + r ,1] := u[i-1]; | |
if (i + g <= MAX_FALSE_COLORS) and (i < 3*n) then J[i + g, 2] := u[i-1]; | |
if (i + offset <= 3*n - 1) then J[i,3] := u[i- 1 + offset]; | |
end; | |
for i := 1 to MAX_FALSE_COLORS do | |
begin | |
if J[i, 1] > 255 then | |
J[i, 1] := 255; | |
if J[i, 2] > 255 then | |
J[i, 2] := 255; | |
if J[i, 3] > 255 then | |
J[i, 3] := 255; | |
end; | |
for i := 1 to MAX_FALSE_COLORS - 1 do | |
begin | |
falseColorTable[i].rgbtBlue := J[i+1,3]; | |
falseColorTable[i].rgbtGreen := J[i+1,2]; | |
falseColorTable[i].rgbtRed := J[i+1,1]; | |
end; | |
falseColorTable[MAX_FALSE_COLORS - 1].rgbtBlue := 255; | |
falseColorTable[MAX_FALSE_COLORS - 1].rgbtGreen := 255; | |
falseColorTable[MAX_FALSE_COLORS - 1].rgbtRed := 255; | |
falseColorTable[0].rgbtBlue := 0; | |
falseColorTable[0].rgbtGreen := 0; | |
falseColorTable[0].rgbtRed := 0; | |
end; | |
function TMainform.GetActiveFile: TObject; {returns the file associated with the MDI window} | |
begin | |
Result := nil; | |
if MDIChildCount > 0 then | |
if MDIChildren[0] is TViewerFrm then | |
Result := (MDIChildren[0] as TViewerFrm).MPFile | |
else if MDIChildren[0] is TAnalogFrm then | |
Result := (MDIChildren[0] as TAnalogFrm).MPFile; | |
end; | |
{********************************* PUBLIC *************************************} | |
procedure TMainform.WMDROPFILES(var Message: TMessage); | |
var szFileName: array[0..255] of Char; | |
fileCount, i: integer; | |
s: string; | |
begin | |
fileCount := DragQueryFile(HDROP(Message.wParam), $FFFFFFFF, nil, 256); | |
try | |
if fileCount > 0 then | |
for i := 0 to fileCount - 1 do | |
if DragQueryFile(HDROP(Message.wParam), i, @szFileName, 256) > 0 then | |
begin | |
s := szFileName; | |
FileList.Open(s); | |
end; | |
finally | |
DragFinish(HDROP(Message.wParam)); | |
end; | |
end; | |
procedure TMainform.WMPOSTSHOWMSG(var Message: TMessage); | |
begin | |
if ParamCount > 0 then | |
FileList.Open(ParamStr(1)) | |
else | |
OpenFile1Click(nil); | |
end; | |
{**************************** CREATION - DESTRUCTION **************************} | |
procedure TMainform.FormCreate(Sender: TObject); | |
var reg: TRegistry; | |
keyName, keyValue: string; | |
TempKey: HKey; | |
Disposition: Integer; | |
begin | |
AVIFileInit; | |
InitializeColorTables; | |
fileList := TFileList.Create; | |
VariantInit(matlab); | |
{Associates file extension: CODE DOES NOT WORK} | |
{Opens root} | |
TempKey := 0; | |
keyName := '.mpd'; | |
if RegCreateKeyEx(HKEY_CLASSES_ROOT, PChar(keyName), 0, nil, REG_OPTION_NON_VOLATILE, | |
KEY_ALL_ACCESS, nil, TempKey, @Disposition) = ERROR_SUCCESS then | |
begin | |
keyValue := 'MPView'; | |
RegSetValue(TempKey, nil, REG_SZ, PChar(keyValue), Length(keyValue)); | |
RegCloseKey(TempKey); | |
end; | |
TempKey := 0; | |
keyName := 'MPView'; | |
if RegCreateKeyEx(HKEY_CLASSES_ROOT, PChar(keyName), 0, nil, REG_OPTION_NON_VOLATILE, | |
KEY_ALL_ACCESS, nil, TempKey, @Disposition) = ERROR_SUCCESS then | |
RegCloseKey(TempKey); | |
TempKey := 0; | |
keyName := 'MPView\DefaultIcon'; | |
if RegCreateKeyEx(HKEY_CLASSES_ROOT, PChar(keyName), 0, nil, REG_OPTION_NON_VOLATILE, | |
KEY_ALL_ACCESS, nil, TempKey, @Disposition) = ERROR_SUCCESS then | |
begin | |
keyValue := ParamStr(0) + ',0'; | |
RegSetValue(TempKey, nil, REG_SZ, PChar(keyValue), Length(keyValue)); | |
RegCloseKey(TempKey); | |
end; | |
TempKey := 0; | |
keyName := 'MPView\Shell'; | |
if RegCreateKeyEx(HKEY_CLASSES_ROOT, PChar(keyName), 0, nil, REG_OPTION_NON_VOLATILE, | |
KEY_ALL_ACCESS, nil, TempKey, @Disposition) = ERROR_SUCCESS then | |
RegCloseKey(TempKey); | |
TempKey := 0; | |
keyName := 'MPView\Shell\Open'; | |
if RegCreateKeyEx(HKEY_CLASSES_ROOT, PChar(keyName), 0, nil, REG_OPTION_NON_VOLATILE, | |
KEY_ALL_ACCESS, nil, TempKey, @Disposition) = ERROR_SUCCESS then | |
begin | |
keyValue := '&Open'; | |
RegSetValue(TempKey, nil, REG_SZ, PChar(keyValue), Length(keyValue)); | |
RegCloseKey(TempKey); | |
end; | |
TempKey := 0; | |
keyName := 'MPView\Shell\Open\Command'; | |
if RegCreateKeyEx(HKEY_CLASSES_ROOT, PChar(keyName), 0, nil, REG_OPTION_NON_VOLATILE, | |
KEY_ALL_ACCESS, nil, TempKey, @Disposition) = ERROR_SUCCESS then | |
begin | |
keyValue := ParamStr(0) + ' %1'; | |
RegSetValue(TempKey, nil, REG_SZ, PChar(keyValue), Length(keyValue)); | |
RegCloseKey(TempKey); | |
end; | |
reg := TRegistry.Create; | |
with reg do | |
try | |
RootKey := HKEY_CURRENT_USER; | |
if OpenKey('\Software\Microsoft\Windows\CurrentVersion\Extensions', True) | |
then if ReadString('MPD') = '' then | |
WriteString('MPD', ParamStr(0)); | |
CloseKey; | |
finally | |
Free; | |
end; | |
{Drag and Drop} | |
DragAcceptFiles(Handle, True); | |
end; | |
procedure TMainform.FormShow(Sender: TObject); | |
var regini: TRegistryIniFile; | |
begin | |
regini := TRegistryIniFile.Create(sAppName); | |
with regini do | |
begin | |
FileList.dataDirectory := ExcludeTrailingBackslash(ReadString(sSection, sDirectory, '')); | |
bLocalMatlabServer := ReadBool(sSection, sbLocalServer, True); | |
remoteMatlabServer := ReadString(sSection, sRemoteServerLocation, ''); | |
if not DirectoryExists(FileList.dataDirectory) then | |
fileList.dataDirectory := ExcludeTrailingBackslash(ExtractFilePath(ParamStr(0))); | |
RestorePosFromRegistry(self, regini, sSection, sEntry, True); | |
Free; | |
end; | |
PostMessage(Handle, WM_POSTSHOWMSG, 0, 0); | |
end; | |
procedure TMainform.FormClose(Sender: TObject; var Action: TCloseAction); | |
var regini: TRegistryIniFile; | |
begin | |
regini := TRegistryIniFile.Create(sAppName); | |
with regini do | |
begin | |
WriteBool(sSection, sbLocalServer, bLocalMatlabServer); | |
WriteString(sSection, sRemoteServerLocation, remoteMatlabServer); | |
WriteString(sSection, sDirectory, FileList.dataDirectory); | |
SavePosToRegistry(self, regini, sSection, sEntry); | |
Free; | |
end; | |
{Drag and Drop} | |
DragAcceptFiles(Handle, False); | |
end; | |
procedure TMainform.FormDestroy(Sender: TObject); | |
begin | |
fileList.Free; | |
AVIFileExit; | |
end; | |
{************************************ MENUS ***********************************} | |
procedure TMainform.NewFile1Click(Sender: TObject); | |
begin | |
if ActiveFile <> nil then | |
fileList.NewFile(ActiveFile as TMPFile); | |
end; | |
procedure TMainform.OpenFile1Click(Sender: TObject); | |
begin | |
OpenDialog1.InitialDir := ExcludeTrailingBackslash(FileList.dataDirectory); | |
if OpenDialog1.Execute then | |
FileList.Open(OpenDialog1.Filename); | |
end; | |
procedure TMainform.SaveFileAs1Click(Sender: TObject); | |
begin | |
if MDIChildCount > 0 then | |
if MDIChildren[0] is TViewerFrm then | |
if (MDIChildren[0] as TViewerFrm).mpFile.IsMemoryFile then | |
begin | |
if (MDIChildren[0] as TViewerFrm).mpFile.FrameCount > 0 then | |
begin | |
with SaveDialog1 do | |
begin | |
DefaultExt := 'MPD'; | |
Filter := 'MPD Files (*.MPD)|*.MPD|All Files (*.*)|*.*'; | |
Title := 'Save Workspace As'; | |
end; | |
if SaveDialog1.Execute then | |
fileList.SaveFileAs | |
((MDIChildren[0] as TViewerFrm).MPFile, SaveDialog1.Filename); | |
end | |
else | |
MessageDlg('Workspace ' + (MDIChildren[0] as TViewerFrm).mpFile.Filename + | |
' has no frames to save.', mtInformation, [mbOK], 0); | |
end; | |
{ else if MDIChildren[0] is TAnalogFrm then | |
begin | |
end | |
else if MDIChildren[0] is TROIFrm then | |
begin | |
end; } | |
end; | |
procedure TMainform.AnalogDataAs1Click(Sender: TObject); | |
var fromFrame, toFrame: integer; | |
savedCursor: TCursor; | |
bASCII: boolean; | |
begin | |
if MDIChildCount > 0 then | |
if MDIChildren[0] is TAnalogFrm then | |
if (MDIChildren[0] as TAnalogFrm).mpFile.FrameCount > 0 then | |
begin | |
bASCII := (MessageDlg('Do you want to save the file as plain ASCII (Yes) or Unicode (No)?', | |
mtInformation, [mbYes, mbNo], 0)= mrYes); | |
{strange - "with" construct with CopyAnalogDlg or (MDIChildren[0] fail at run-time)} | |
CopyAnalogDlg.RadioButton1.Checked := (MDIChildren[0] as TAnalogFrm).mpFile.AnalogChEnabled[2]; | |
CopyAnalogDlg.RadioButton1.Enabled := (MDIChildren[0] as TAnalogFrm).mpFile.AnalogChEnabled[2]; | |
CopyAnalogDlg.RadioButton2.Checked := (MDIChildren[0] as TAnalogFrm).mpFile.AnalogChEnabled[3]; | |
CopyAnalogDlg.RadioButton2.Enabled := (MDIChildren[0] as TAnalogFrm).mpFile.AnalogChEnabled[3]; | |
CopyAnalogDlg.SpinEdit1.MaxValue := (MDIChildren[0] as TAnalogFrm).mpFile.FrameCount; | |
CopyAnalogDlg.SpinEdit1.Value := 1; | |
CopyAnalogDlg.SpinEdit2.MaxValue := (MDIChildren[0] as TAnalogFrm).mpFile.FrameCount; | |
CopyAnalogDlg.SpinEdit2.Value := (MDIChildren[0] as TAnalogFrm).mpFile.FrameCount; | |
if CopyAnalogDlg.ShowModal = mrOK then | |
begin | |
fromFrame := CopyAnalogDlg.SpinEdit1.Value - 1; | |
toFrame := CopyAnalogDlg.SpinEdit2.Value - 1; | |
if (fromFrame >= 0) and (fromFrame <= (MDIChildren[0] as TAnalogFrm).mpFile.FrameCount - 1) and | |
(toFrame >= 0) and (toFrame <= (MDIChildren[0] as TAnalogFrm).mpFile.FrameCount - 1) and | |
(fromFrame <= toFrame) then | |
begin | |
with SaveDialog1 do | |
begin | |
DefaultExt := 'TXT'; | |
Filter := 'Text Files (*.TXT)|*.TXT|All Files (*.*)|*.*'; | |
Title := 'Save Analog Data In Text File'; | |
end; | |
if SaveDialog1.Execute then | |
begin | |
savedCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
(MDIChildren[0] as TAnalogFrm).mpFile.SaveChannelsToFile(bASCII, | |
SaveDialog1.Filename, | |
CopyAnalogDlg.RadioButton1.Checked and CopyAnalogDlg.RadioButton1.Enabled, | |
CopyAnalogDlg.RadioButton2.Checked and CopyAnalogDlg.RadioButton2.Enabled, | |
fromFrame, toFrame); | |
finally | |
Screen.Cursor := savedCursor; | |
end; | |
end; | |
end | |
else | |
MessageDlg('Invalid frame indices.', mtError, [mbOK], 0); | |
end; {showmodal} | |
end {frame count > 0} | |
else | |
MessageDlg('Analog Window ' + (MDIChildren[0] as TAnalogFrm).mpFile.Filename + | |
' has no data to save.', mtInformation, [mbOK], 0); | |
end; | |
procedure TMainform.About1Click(Sender: TObject); | |
begin | |
AboutDlg.ShowModal; | |
end; | |
procedure TMainform.Options1Click(Sender: TObject); | |
begin | |
if not VarIsEmpty(matlab) then Exit; | |
if OptDlg.ShowModal = mrOK then | |
try | |
Screen.Cursor := crHourGlass; | |
VariantInit(matlab); | |
if bLocalMatlabServer then | |
begin | |
matlab := CreateOLEObject('Matlab.Application'); | |
matlab.Visible := 1; | |
end | |
else | |
matlab := CreateRemoteCOMObject(remoteMatlabServer, DIID_DIMLApp); | |
mconsole := Tmconsole.Create(self); | |
mconsole.Show; | |
finally | |
Screen.Cursor := crDefault; | |
end; | |
if VarIsEmpty(matlab) then | |
MessageDlg('MPView cannot start Matlab.', mtError, [mbOK], 0); | |
end; | |
procedure TMainform.StopMatlab1Click(Sender: TObject); | |
begin | |
if not(VarIsEmpty(matlab)) then | |
begin | |
VariantClear(matlab); | |
VariantInit(matlab); | |
mconsole.Close; | |
mconsole := nil; | |
end; | |
end; | |
procedure TMainform.FileInformation1Click(Sender: TObject); | |
begin | |
if ActiveFile <> nil then | |
begin | |
FileInfoDlg.Fill(ActiveFile as TMPFile); | |
FileInfoDlg.ShowModal; | |
end; | |
end; | |
procedure TMainform.Close1Click(Sender: TObject); | |
begin | |
if ActiveFile <> nil then | |
(ActiveFile as TMPFile).Close(self) | |
else | |
ActiveMDIChild.Close; | |
end; | |
procedure TMainform.FormCloseQuery(Sender: TObject; var CanClose: Boolean); | |
begin | |
bAppClosing := True; | |
end; | |
procedure TMainform.Exit1Click(Sender: TObject); | |
begin | |
Close; | |
end; | |
procedure TMainform.Tile1Click(Sender: TObject); | |
begin | |
Tile; | |
end; | |
procedure TMainform.Cascade1Click(Sender: TObject); | |
begin | |
Cascade; | |
end; | |
procedure TMainform.ArrangeAll1Click(Sender: TObject); | |
begin | |
ArrangeIcons; | |
end; | |
procedure TMainform.ROIDataAs1Click(Sender: TObject); | |
var savedCursor: TCursor; | |
bASCII: boolean; | |
padding: integer; | |
begin | |
if MDIChildCount > 0 then | |
if MDIChildren[0] is TROIFrm then | |
if (MDIChildren[0] as TROIFrm).toFrame - (MDIChildren[0] as TROIFrm).fromFrame > 0 then | |
begin | |
bASCII := (MessageDlg('Do you want to save the file as plain ASCII (Yes) or Unicode (No)?', | |
mtInformation, [mbYes, mbNo], 0)= mrYes); | |
if MessageDlg('Do you want to add extra data points between ROI values?', mtInformation, | |
[mbYes, mbNo], 0) = mrYes then | |
begin | |
try | |
padding := StrToInt(InputBox('Data Points Between ROI Values', 'Enter total data points', '1')); | |
except | |
padding := 0; | |
end; | |
end | |
else | |
padding := 1; | |
if (padding > 0) and (padding < 10000000) then | |
begin | |
with SaveDialog1 do | |
begin | |
DefaultExt := 'TXT'; | |
Filter := 'Text Files (*.TXT)|*.TXT|All Files (*.*)|*.*'; | |
Title := 'Save ROI Data In Text File'; | |
end; | |
if SaveDialog1.Execute then | |
begin | |
savedCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
(MDIChildren[0] as TROIFrm).SaveDataToFile(bASCII, padding, | |
SaveDialog1.Filename); | |
finally | |
Screen.Cursor := savedCursor; | |
end; | |
end; | |
end | |
else | |
MessageDlg('Invalid padding value.', mtError, [mbOK], 0); | |
end {frame count > 0} | |
else | |
MessageDlg('ROI Window ' + MDIChildren[0].Caption + | |
' has no data to save.', mtInformation, [mbOK], 0); | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit mconsolefrm; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
StdCtrls, ActiveX, ComObj; | |
type | |
Tmconsole = class(TForm) | |
Memo1: TMemo; | |
procedure FormClose(Sender: TObject; var Action: TCloseAction); | |
procedure FormShow(Sender: TObject); | |
procedure Memo1KeyUp(Sender: TObject; var Key: Word; | |
Shift: TShiftState); | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
end; | |
var | |
mconsole: Tmconsole; | |
implementation | |
uses mainfrm {, Variants}; | |
{$R *.DFM} | |
procedure Tmconsole.FormClose(Sender: TObject; var Action: TCloseAction); | |
begin | |
if not Mainform.bAppClosing then | |
begin | |
if not(VarIsEmpty(Mainform.matlab)) then | |
begin | |
VariantClear(Mainform.matlab); | |
VariantInit(Mainform.matlab); | |
end; | |
Action := caFree; | |
end; | |
end; | |
procedure Tmconsole.FormShow(Sender: TObject); | |
begin | |
Memo1.Lines.Add('Enter Matlab code after the prompt.'); | |
Memo1.Text := Memo1.Text + '>'; | |
Memo1.SelStart := Length(Memo1.Text); {sets before CR} | |
Memo1.SelLength := 0; | |
end; | |
procedure Tmconsole.Memo1KeyUp(Sender: TObject; var Key: Word; | |
Shift: TShiftState); | |
var v: Variant; | |
s, sm: string; | |
i: integer; | |
begin | |
if Key = 13 {Line feed} then | |
begin | |
{look for line containing the last caret} | |
s := Memo1.Lines[Memo1.Lines.Count - 1]; | |
if s[1] = '>' then | |
begin | |
{removes '>'} | |
sm := Copy(s, 2, Length(s) - 1); | |
v := sm; {prepares variant} | |
sm := VarToStr(Mainform.matlab.Execute(v)); | |
{adds a CR before a LF} | |
s := ''; | |
if Length(sm) > 0 then | |
for i := 1 to Length(sm) do | |
begin | |
if sm[i] = Chr(10) then s := s + Chr(13); | |
s := s + sm[i]; | |
end; | |
Memo1.Lines.Add(s); | |
end; | |
Memo1.Text := Memo1.Text + '>'; | |
Memo1.Refresh; | |
Memo1.SelStart := Length(Memo1.Text); | |
Memo1.SelLength := 0; | |
end; | |
end; | |
initialization | |
mconsole := nil; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit mpdevices; | |
{ **************************************************************************** } | |
{*} {*} | |
{*} INTERFACE {*} | |
{* This unit abstracts the devices used to run the microscope. {*} | |
{ **************************************************************************** } | |
uses Classes, Windows, Controls, AnalogStimDef, MPUnit, AdPort, MPSCAN_PC_TLB, AutoXYTable, | |
AutoZStepper, AutoShutter, MMSystem, AutoLaser, XPSThreadU, GalilThreadU, | |
SysUtils, Messages; | |
const | |
// the number of steps sent to the galil is computed from | |
// (number of microns to move) * GALIL_STEPPER_RESOLUTION | |
GALIL_STEPPER_RESOLUTION_Z = 16/5; // 5 microns per 16 steps} | |
GALIL_STEPPER_RESOLUTION_XY = 3200/508; //3200/508; // RIG - 16/5 for L2 and L1 front rig, 3200/508 for L1 back rig | |
type | |
TDeviceState = (dsNotInstalled, dsInstalled, dsNotFound, dsDetected); | |
{generic callback to update user interface; used by slow devices (serial port based)} | |
// obsolete Dec 19 2005; TPositionCallback = procedure of Object; | |
TMPScanDevice = class | |
private | |
fDeviceState: TDeviceState; | |
function GetDeviceState: TDeviceState; virtual; | |
public | |
name: string; | |
procedure Connect; virtual; | |
property deviceStatus: TDeviceState read GetDeviceState; | |
end; | |
{******************************* NI-DAQ Board *********************************} | |
TNIDAQBoard = class(TMPScanDevice) | |
private | |
fDigitalPort: integer; | |
deviceCode: int16; | |
fbLogicLow: boolean; | |
function GetBoardIndex: integer; virtual; | |
procedure SetBoardIndex(newIndex: integer); virtual; | |
procedure SetDigitalPort(dioValue: integer); | |
public | |
procedure SetDigitalBit(bitIndex: integer; value: boolean); {takes into account logic} | |
property boardIndex: integer read GetBoardIndex write SetBoardIndex; | |
property DigitalPort: integer read fDigitalPort write SetDigitalPort; | |
end; | |
{TMultifunctionBoard is currently a PCI-6110E. It puts the 20 MHz clock and the | |
start of acquisition signals on RTSI lines 0 and 1} | |
TMultifunctionBoard = class(TNIDAQBoard) | |
private | |
function GetInvertPreamps: boolean; | |
function GetBoardIndex: integer; override; | |
function GetLogicLow: boolean; | |
function GetMaxAnalogOutDigitalValue: integer; | |
function GetTriggerLine: integer; | |
function GetPMTOffsets(chIndex: integer): int16; | |
function GetTTLTriggerPFILine: integer; | |
function GetT1(mirror: integer): integer; | |
function GetT2(mirror: integer): integer; | |
function GetDeltaT(mirror: integer): integer; | |
procedure SetInvertPreamps(value: boolean); | |
procedure SetBoardIndex(newIndex: integer); override; | |
procedure SetLogicLow(value: boolean); | |
procedure SetPMTOffsets(chIndex: integer; value: int16); | |
procedure SetTTLTriggerPFILine(lineIndex: integer); | |
procedure SetT1(mirror: integer; value: integer); | |
procedure SetT2(mirror: integer; value: integer); | |
procedure SetDeltaT(mirror: integer; value: integer); | |
public | |
{feedforward parameters} | |
procedure Connect; override; | |
constructor Create; | |
{original Earl Dolnick's design: all logic 1s are 0s on the bus} | |
property LogicLow: boolean read GetLogicLow write SetLogicLow; | |
property MaxAnalogOutDigitalValue: integer read GetMaxAnalogOutDigitalValue; | |
property PMTOffsets[chIndex: integer]: int16 read GetPMTOffsets write SetPMTOffsets; | |
{image acquisition TTL triggering} | |
property TTLTriggerPFILine: integer read GetTTLTriggerPFILine write SetTTLTriggerPFILine; | |
property TriggerLine: integer read GetTriggerLine; {returns code for PFI_X lines} | |
{feedforward mirror correction parameters} | |
property T1[mirror: integer]: integer read GetT1 write SetT1; | |
property T2[mirror: integer]: integer read GetT2 write SetT2; | |
property DeltaT[mirror: integer]: integer read GetDeltaT write SetDeltaT; | |
{added 12-11-07 for commercial PMT preamps that invert polarity} | |
property bInvertPreamps: boolean read GetInvertPreamps write SetInvertPreamps; | |
end; | |
{Takes care of analog stimulation output. To minize bus traffic during image | |
acquisition, analog stimulation pattern is pre-loaded to the analog output board | |
FIFO memory. Sets its own clock to RTSI_0 and start of data out to RTSI_1} | |
TAnalogOutputBoard = class(TNIDAQBoard) | |
private | |
fAnalogOutputEnabled: boolean; | |
fOutputRange: double; | |
cStimBufferSize: integer; {in samples} | |
pStimBuffer: TpFrameData; | |
fLoaded: boolean; | |
FIFOSampleCount: integer; {default: 8192} | |
procedure AllocateStimBuffer; | |
procedure DestroyStimBuffer; | |
function GetAnalogChConvFactors(chIndex: integer): double; | |
function GetAnalogChNames(chIndex: integer): string; | |
function GetAnalogChPrefixes(chIndex: integer): TPrefix; | |
function GetAnalogChUnits(chIndex: integer): string; | |
function GetAnalogChZeroOffset(chIndex: integer): double; | |
function GetBoardIndex: integer; override; | |
function GetInstalled: boolean; virtual; | |
function GetTotalSampleCount(const newParams: TAnalogStimRec): integer; | |
procedure ReloadStimParams; | |
procedure SetAnalogChConvFactors(chIndex: integer; value: double); | |
procedure SetAnalogChNames(chIndex: integer; value: string); | |
procedure SetAnalogChPrefixes(chIndex: integer; value: TPrefix); | |
procedure SetAnalogChUnits(chIndex: integer; value: string); | |
procedure SetAnalogChZeroOffset(chIndex: integer; value: double); | |
procedure SetAnalogOutputEnabled(newAnalogOut: boolean); | |
procedure SetBoardIndex(newIndex: integer); override; | |
procedure SetInstalled(value: boolean); virtual; | |
function ValidateStimParams(const newParams: TAnalogStimRec): boolean; | |
public | |
analogStimParams: TAnalogStimRec; | |
procedure AnalogOut(chIndex: integer; value: double); | |
function AnalogToDigital(chIndex: integer; value: double): int16; | |
procedure Connect; override; | |
function DigitalToAnalog(chIndex: integer; value: int16): double; | |
function LoadAnalogStimParams(const newParams: TAnalogStimRec): boolean; | |
function OpenAnalogStimulation(const stimFilename: string): boolean; | |
procedure SaveAnalogStimulation(const stimFilename: string); | |
procedure StartAnalogStimulation; | |
function StopAnalogStimulation: boolean; {returns True or False in incremental | |
incremental mode when another stimulation needs to be issued} | |
constructor Create; | |
destructor Destroy; override; | |
property AnalogOutputEnabled: boolean read fAnalogOutputEnabled write SetAnalogOutputEnabled; | |
property AnalogChConvFactors[chIndex: integer]: double read GetAnalogChConvFactors write SetAnalogChConvFactors; | |
property AnalogChNames[chIndex: integer]: string read GetAnalogChNames write SetAnalogChNames; | |
property AnalogChPrefixes[chIndex: integer]: TPrefix read GetAnalogChPrefixes write SetAnalogChPrefixes; | |
property AnalogChUnits[chIndex: integer]: string read GetAnalogChUnits write SetAnalogChUnits; | |
property AnalogChZeroOffsets[chIndex: integer]: double read GetAnalogChZeroOffset write SetAnalogChZeroOffset; | |
property Installed: boolean read GetInstalled write SetInstalled; | |
property Loaded: boolean read fLoaded; | |
property OutputRange: double read fOutputRange; {bipolar output = +/-OutputRange} | |
end; | |
{opticsOutputBoard provides up to 4 analog output channels to control the Z | |
piezo stepper, Pockels cell etc... 20 MHz time base provided via the RTSI bus; | |
All timings relative to the 20 MHz time base of the PCI-6110E. | |
Sets its own clock to RTSI_0 and start of data out to RTSI_1} | |
TOpticsOutputBoard = class(TAnalogOutputBoard) | |
private | |
function GetBoardIndex: integer; override; | |
function GetInstalled: boolean; override; | |
procedure SetBoardIndex(newIndex: integer); override; | |
procedure SetInstalled(value: boolean); override; | |
{*public | |
procedure AnalogOutF(chIndex: integer; value: double); *} | |
end; | |
{Uses RTSI_2 to get pixel clock} | |
TPhotonCountingBoard = class(TNIDAQBoard) | |
private | |
function GetBoardIndex: integer; override; | |
function GetInstalled: boolean; | |
procedure SetBoardIndex(newIndex: integer); override; | |
procedure SetInstalled(value: boolean); | |
public | |
procedure Connect; override; | |
constructor Create; | |
destructor Destroy; override; | |
property Installed: boolean read GetInstalled write SetInstalled; | |
end; | |
{******************************** Laser Shutter *******************************} | |
TLaserShutter = class(TMPScanDevice) | |
private | |
fbClosed: boolean; | |
function GetAnalogBoardControlsShutter: boolean; | |
function GetCloseAfterSection: boolean; | |
function GetMultifunctionDIOIndex: integer; | |
function GetOpenDelay: integer; | |
procedure SetAnalogBoardControlsShutter(value: boolean); | |
procedure SetCloseAfterSection(value: boolean); | |
procedure SetClosed(bClosed: boolean); | |
procedure SetMultifunctionDIOIndex(newIndex: integer); | |
procedure SetOpenDelay(newDelay: integer); | |
public | |
autoObject: IMPLaserShutter; | |
procedure Connect; override; | |
procedure OpenShutter; | |
procedure Wait(nms: integer); | |
constructor Create; | |
destructor Destroy; override; | |
property AnalogBoardControlsShutter: boolean read GetAnalogBoardControlsShutter | |
write SetAnalogBoardControlsShutter; | |
property Closed: boolean read fbClosed write SetClosed; | |
property CloseAfterSection: boolean read GetCloseAfterSection write SetCloseAfterSection; | |
property MultifunctionDIOIndex: integer read GetMultifunctionDIOIndex write SetmultifunctionDIOIndex; | |
property OpenDelay: integer read GetOpenDelay write SetOpenDelay; | |
end; | |
{ | |
TOriginalShutter = class(TLaserShutter) | |
procedure SetDeviceState(newState: TDeviceState); override; | |
end; | |
} | |
{******************************* Z-stepper table ******************************} | |
TZStepper = class(TMPScanDevice) | |
private | |
bTimerActive: boolean; | |
zTimer: MMResult; | |
minTimerResolution, maxTimerResolution: integer; | |
curFastRepeatCount: integer; | |
bFastScanInProgress, fBusy: boolean; | |
startFastScanPosition, | |
fStepSize: double; | |
function GetCOMPort: integer; | |
function GetCOMSpeed: integer; | |
function GetInvertZ: boolean; | |
function GetSpeed: integer; | |
procedure SetCOMPort(value: integer); | |
procedure SetCOMSpeed(value: integer); | |
procedure SetInvertZ(value: boolean); | |
procedure SetSpeed(newspeed: integer); virtual; | |
procedure SetZPosition(newPos: double); | |
public | |
fZPosition: double; | |
autoObject: IMPZStepper; | |
procedure OnMoveStarted; {updates user interface} | |
procedure OnMoveFinished; | |
{asynchronous calls} | |
{1: slowest, 10: fastest} | |
procedure GetZ(var newZ: double); virtual; | |
procedure MoveToRelativeZ(newDeltaZ: double); virtual; | |
procedure SetZ(var newZ: double); virtual; | |
{retuns the time (in s) it takes to do zTravel at speedIndex (1..60)} | |
function TravelTime(zTravel: integer; speedIndex: integer): double; virtual; | |
procedure StartFastScan; virtual; | |
procedure StopFastScan; virtual; | |
procedure StopMove; | |
{synchronous calls: MoveToZ, ReadZ, ShiftByZ} | |
procedure MoveToZ(newZ: double); virtual; | |
function ReadZ: double; virtual; | |
procedure ShiftByZ(deltaZ: double); virtual; | |
property Busy: boolean read fBusy write fBusy; | |
property COMPort: integer read GetCOMPort write SetCOMPort; | |
property COMSpeed: integer read GetCOMSpeed write SetCOMSpeed; | |
property MovingZ: boolean read fBusy; | |
property FastScanInProgress: boolean read bFastScanInProgress; | |
property InvertZ: boolean read GetInvertZ write SetInvertZ; {inverts z motion} | |
property ZPosition: double read fZPosition write SetZPosition; | |
property stepSize: double read fStepSize; {in microns} | |
property Speed: integer read GetSpeed write SetSpeed; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
type | |
TZSequence = array[0..1] of int16; {Z-axis up or down sequence} | |
TZSequenceArray = array[0..1000000] of TZSequence; | |
TpZSequenceArray = ^TZSequenceArray; | |
TEarlStepper = class(TZStepper) | |
private | |
zPattern: int32; | |
curZsequenceCount, zsequenceCount: integer; | |
procedure SetSpeed(newspeed: integer); override; | |
public | |
procedure Connect; override; | |
procedure GetZ(var newZ: double); override; | |
procedure MoveToRelativeZ(newDeltaZ: double); override; | |
procedure SetZ(var newZ: double); override; | |
function TravelTime(zTravel: integer; speedIndex: integer): double; override; | |
procedure MoveToZ(newZ: double); override; | |
function ReadZ: double; override; | |
procedure ShiftByZ(deltaZ: double); override; | |
procedure StartFastScan; override; | |
procedure StopFastScan; override; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{Object created when microscope uses a MP285 micromanipulator to move the XYZ stage. | |
Module hardconfig enforces the rule that if MP285 is used for XY, MP285 is used for Z. | |
A TZMP285 and a TXYMP285 objects are instantiated. They all refer to the TXYZMP285 object | |
(not seen by user) | |
} | |
TZMP285 = class(TZStepper) | |
function GetDeviceState: TDeviceState; override; | |
procedure SetSpeed(speedIndex: integer); override; | |
public | |
procedure Connect; override; | |
procedure GetZ(var newZ: double); override; | |
procedure MoveToRelativeZ(newDeltaZ: double); override; | |
procedure SetZ(var newZ: double); override; | |
procedure MoveToZ(newZ: double); override; | |
function ReadZ: double; override; | |
procedure ShiftByZ(deltaZ: double); override; | |
function TravelTime(zTravel: integer; speedIndex: integer): double; override; | |
procedure StartFastScan; override; | |
procedure StopFastScan; override; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{Object created when microscope uses a ESP300 micromanipulator to move the XYZ stage. | |
Module hardconfig enforces the rule that if ESP300 is used for XY, ESP300 is used for Z. | |
A TZESP300 and a TXYESP300 objects are instantiated. They all refer to the TXYZESP300 object | |
(not seen by user) | |
} | |
TZESP300 = class(TZStepper) | |
function GetDeviceState: TDeviceState; override; | |
procedure SetSpeed(speedIndex: integer); override; | |
public | |
procedure Connect; override; | |
procedure GetZ(var newZ: double); override; | |
procedure MoveToRelativeZ(newDeltaZ: double); override; | |
procedure SetZ(var newZ: double); override; | |
procedure MoveToZ(newZ: double); override; | |
function ReadZ: double; override; | |
procedure ShiftByZ(deltaZ: double); override; | |
function TravelTime(zTravel: integer; speedIndex: integer): double; override; | |
procedure StartFastScan; override; | |
procedure StopFastScan; override; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{interfaces with the X-Y-Z Newport XPS controller} | |
TZ_XPS = class(TZStepper) | |
function GetDeviceState: TDeviceState; override; | |
procedure SetSpeed(speedIndex: integer); override; | |
public | |
procedure Connect; override; | |
procedure GetZ(var newZ: double); override; | |
procedure MoveToRelativeZ(newDeltaZ: double); override; | |
procedure SetZ(var newZ: double); override; | |
procedure MoveToZ(newZ: double); override; | |
function ReadZ: double; override; | |
procedure ShiftByZ(deltaZ: double); override; | |
function TravelTime(zTravel: integer; speedIndex: integer): double; override; | |
procedure StartFastScan; override; | |
procedure StopFastScan; override; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{Object created when microscope uses a Galil DMC-40x0 controller to move the XYZ stage. | |
Module hardconfig enforces the rule that if DMC is used for XY, DMC is used for Z. | |
A T_ZDMC40 and a TXY_DMC40 objects are instantiated. They all refer to the TDMC40 object | |
(not seen by user) | |
} | |
{interfaces with the X-Y-Z Galil DMC controller} | |
TZ_DMC40 = class(TZStepper) | |
function GetDeviceState: TDeviceState; override; | |
public | |
procedure Connect; override; | |
procedure GetZ(var newZ: double); override; | |
procedure MoveToRelativeZ(newDeltaZ: double); override; | |
procedure SetZ(var newZ: double); override; | |
procedure MoveToZ(newZ: double); override; | |
function ReadZ: double; override; | |
procedure ShiftByZ(deltaZ: double); override; | |
function TravelTime(zTravel: integer; speedIndex: integer): double; override; | |
procedure StartFastScan; override; | |
procedure StopFastScan; override; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{**************************** X-Y Translation table ***************************} | |
{All moves in microns} | |
{Any device using a COM port should release it on being destroyed} | |
TXYTable = class(TMPScanDevice) | |
private | |
fBusy: boolean; | |
pNewX, pNewY: PInteger; | |
desiredX, desiredY, iterationCount: integer; | |
function GetCOMPort: integer; | |
function GetCOMSpeed: integer; | |
function GetInvertX: boolean; | |
function GetInvertY: boolean; | |
function GetSpeed: integer; | |
procedure SetCOMPort(portIndex: integer); | |
procedure SetCOMSpeed(portSpeed: integer); | |
procedure SetInvertX(bInvert: boolean); | |
procedure SetInvertY(bInvert: boolean); | |
procedure SetSpeed(value: integer); virtual; | |
public | |
fXPosition, fYPosition: integer; | |
autoObject: IMPXYTable; | |
reply: string; // 8-6-09 ALS | |
procedure OnMoveStarted; {updates user interface} | |
procedure OnMoveFinished; | |
{asynchronous calls} | |
procedure GetXY(var newX, newY: integer); virtual; | |
procedure SetXY(var newX, newY: integer); virtual; | |
procedure SetRelativeXY(deltaX, deltaY: integer); virtual; | |
{synchronous calls: return when complete} | |
procedure MoveToXY(newX, newY: integer); virtual; | |
procedure ReadXY(var x, y: integer); virtual; | |
procedure ShiftByXY(deltaX, deltaY: integer); virtual; | |
procedure | |
XYCommand(const sCommand: string); virtual; | |
procedure GalilWaitForMotionComplete; virtual; | |
property Busy: boolean read fBusy write fBusy; | |
property InvertX: boolean read GetInvertX write SetInvertX; | |
property InvertY: boolean read GetInvertY write SetInvertY; | |
property COMPort: integer read GetCOMPort write SetCOMPort; | |
property COMSpeed: integer read GetCOMSpeed write SetCOMSpeed; | |
property Speed: integer read GetSpeed write SetSpeed; {1: slowest, 20: fastest} | |
property XPosition: integer read fXPosition write fXPosition; | |
property YPosition: integer read fYPosition write fYPosition; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{Finite state machine for various operations} | |
TNeatStatus = (neatOK, | |
neatTERM3, | |
neatMFE, | |
neatAA, | |
neatSE, | |
neatJE, | |
neatREAD, | |
neatREADUPDATE, | |
neatREADCLOSELOOP, | |
neatMOVE, | |
neatMOVECLOSELOOP, | |
neatCOMMAND, | |
neatSETSPEED); | |
TNEAT300 = class(TXYTable) | |
private | |
bNoAnswer: boolean; | |
CaretTriggerHandle, FTriggerHandle, TimerHandle: Word; | |
neatStatus: TNeatStatus; | |
serialPort: TApdCOMPort; | |
s1, s2, s3, sSerial: string; {strings sent back by the serial ports} | |
procedure TriggerData(CP: TObject; TriggerHandle: Word); | |
procedure TriggerAvail(CP: TObject; Count: Word); | |
procedure ParseReturnedString; | |
procedure TimerReceived(CP: TObject; TriggerHandle: Word); | |
procedure SetSpeed(value: integer); override; | |
public | |
procedure Connect; override; | |
procedure GetXY(var newX, newY: integer); override; | |
procedure SetXY(var newX, newY: integer); override; | |
procedure SetRelativeXY(deltaX, deltaY: integer); override; | |
procedure MoveToXY(newX, newY: integer); override; | |
procedure ReadXY(var x, y: integer); override; | |
procedure ShiftByXY(deltaX, deltaY: integer); override; | |
procedure XYCommand(const sCommand: string); override; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
TXYESP300 = class(TXYTable) | |
function GetDeviceState: TDeviceState; override; | |
procedure SetSpeed(value: integer); override; | |
public | |
procedure Connect; override; | |
procedure GetXY(var newX, newY: integer); override; | |
procedure SetXY(var newX, newY: integer); override; | |
procedure SetRelativeXY(deltaX, deltaY: integer); override; | |
procedure MoveToXY(newX, newY: integer); override; | |
procedure ReadXY(var x, y: integer); override; | |
procedure ShiftByXY(deltaX, deltaY: integer); override; | |
procedure XYCommand(const sCommand: string); override; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
TXYMP285 = class(TXYTable) | |
function GetDeviceState: TDeviceState; override; | |
procedure SetSpeed(value: integer); override; | |
public | |
procedure Connect; override; | |
procedure GetXY(var newX, newY: integer); override; | |
procedure SetXY(var newX, newY: integer); override; | |
procedure SetRelativeXY(deltaX, deltaY: integer); override; | |
procedure MoveToXY(newX, newY: integer); override; | |
procedure ReadXY(var x, y: integer); override; | |
procedure ShiftByXY(deltaX, deltaY: integer); override; | |
procedure XYCommand(const sCommand: string); override; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{interfaces with the X-Y-Z Newport XPS controller} | |
TXY_XPS = class(TXYTable) | |
function GetDeviceState: TDeviceState; override; | |
procedure SetSpeed(value: integer); override; | |
public | |
procedure Connect; override; | |
procedure GetXY(var newX, newY: integer); override; | |
procedure SetXY(var newX, newY: integer); override; | |
procedure SetRelativeXY(deltaX, deltaY: integer); override; | |
procedure MoveToXY(newX, newY: integer); override; | |
procedure ReadXY(var x, y: integer); override; | |
procedure ShiftByXY(deltaX, deltaY: integer); override; | |
procedure XYCommand(const sCommand: string); override; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{hidden object controlling the XPS device} | |
TXPS = class(TMPScanDevice) | |
xpsThread: TXPSThread; | |
procedure SetXYSpeed(speedIndex: integer); | |
procedure SetZSpeed(speedIndex: integer); | |
public | |
procedure Connect; override; | |
procedure GetZ(var newZ: double); | |
procedure MoveToRelativeZ(newDeltaZ: double); | |
procedure SetZ(var newZ: double); | |
procedure MoveToZ(newZ: double); | |
function ReadZ: double; | |
procedure ShiftByZ(deltaZ: double); | |
procedure GetXY(var newX, newY: integer); | |
procedure SetXY(var newX, newY: integer); | |
procedure SetRelativeXY(deltaX, deltaY: integer); | |
procedure MoveToXY(newX, newY: integer); | |
procedure ReadXY(var x, y: integer); | |
procedure ShiftByXY(deltaX, deltaY: integer); | |
procedure XYCommand(const sCommand: string); {do nothing: XPS DLL does not allow string commands} | |
procedure FastStackCallback; | |
procedure StartFastStack(fsSpeed: integer; deltaZ: double); | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{************************** Galil DMC-40x controller *************************} | |
{interfaces with the X-Y-Z Galil DMC controller} | |
TXY_DMC40 = class(TXYTable) | |
function GetDeviceState: TDeviceState; override; | |
public | |
procedure Connect; override; | |
procedure GetXY(var newX, newY: integer); override; | |
procedure SetXY(var newX, newY: integer); override; | |
procedure SetRelativeXY(deltaX, deltaY: integer); override; | |
procedure MoveToXY(newX, newY: integer); override; | |
procedure ReadXY(var x, y: integer); override; | |
procedure ShiftByXY(deltaX, deltaY: integer); override; | |
procedure XYCommand(const sCommand: string); override; | |
procedure GalilWaitForMotionComplete; override;//PB | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{hidden object controlling the Galil controller} | |
TDMC40 = class(TMPScanDevice) | |
public | |
GalilThread: TGalilThread; | |
GalilSemaphore: THandle; | |
procedure Connect; override; | |
procedure GetZ(var newZ: double); | |
procedure MoveToRelativeZ(newDeltaZ: double); | |
procedure SetZ(var newZ: double); | |
procedure MoveToZ(newZ: double); | |
function ReadZ: double; | |
procedure ShiftByZ(deltaZ: double); | |
procedure GetXY(var newX, newY: integer); | |
procedure SetXY(var newX, newY: integer); | |
procedure SetRelativeXY(deltaX, deltaY: integer); | |
procedure MoveToXY(newX, newY: integer); | |
procedure ReadXY(var x, y: integer); | |
procedure ShiftByXY(deltaX, deltaY: integer); | |
procedure XYCommand(const sCommand: string); | |
procedure FastStackCallback; | |
procedure StartFastStack(fsSpeed: integer; deltaZ: double); | |
procedure GalilWaitForMotionComplete; | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{****************************** Micromanipulators *****************************} | |
{Operations} | |
TMManOp = (mmanOK, mmanGetPos, mmanSetSpeed, mmanMove, mmanGetPosAndWait, mmanCommand, | |
mmanMoveFast, mmanUpdateDisplay, mmanGetResolution); | |
TMManCoordinates = (mmanX, mmanY, mmanZ); | |
TMManPt = array[mmanX..mmanZ] of double; {coordinates in microns in micromanipulator} | |
TXYZPt = TMManPt; {coordinates in microns for the microscope} | |
TMManPhase = (mpIdle, mpCalibrated, mpTargeted, mpTargeted_Calibrated, mpApproached, mpDescended, mpContacting); | |
TMicromanipulator = class(TMPScanDevice) | |
private | |
fSpeed: integer; {in microns / s} | |
fmmanPhase: TMManPhase; | |
fmanindex: integer; | |
mmanOp: TMManOp; | |
calibMatrix: array[0..2, 0..2] of double; | |
fBusy: boolean; | |
procedure FindDescentPosition(var descentPos: TMManPt); | |
function GetApproachAngle: double; | |
function GetApproachSpeed: integer; | |
function GetAxialIsXZ: boolean; | |
function GetCalibrationShift: integer; | |
function GetCoarseMotion: boolean; virtual; | |
function GetCOMPort: integer; | |
function GetCOMSpeed: integer; | |
function GetContactSpeed: integer; | |
function GetContactStepSize: double; | |
function GetDescentSpeed: integer; | |
function GetInvertX: boolean; | |
function GetInvertY: boolean; | |
function GetInvertZ: boolean; | |
function GetFirstMotionType: TMManCoordinates; | |
function GetmmReadDelay: integer; | |
function GetSecondMotionType: TMManCoordinates; | |
function GetThirdMotionType: TMManCoordinates; | |
function GetstartDescentDistance: double; | |
function GetstopDescentDistance: double; | |
function GetxyzReadDelay: integer; | |
procedure XYZToManipulator(xyzPt: TXYZPt; var manPt: TMManPt); | |
procedure SetApproachAngle(value: double); | |
procedure SetApproachSpeed(value: integer); | |
procedure SetAxialIsXZ(value: boolean); | |
procedure SetCalibrationShift(value: integer); | |
procedure SetCoarseMotion(value: boolean); virtual; | |
procedure SetCOMPort(value: integer); | |
procedure SetCOMSpeed(value: integer); | |
procedure SetContactSpeed(value: integer); | |
procedure SetContactStepSize(value: double); | |
procedure SetDescentSpeed(value: integer); | |
procedure SetInvertX(value: boolean); | |
procedure SetInvertY(value: boolean); | |
procedure SetInvertZ(value: boolean); | |
procedure SetFirstMotionType(value: TMManCoordinates); | |
procedure SetmmReadDelay(value: integer); | |
procedure SetSecondMotionType(value: TMManCoordinates); | |
procedure SetSpeed(value: integer); virtual; {in microns/s} | |
procedure SetThirdMotionType(value: TMManCoordinates); | |
procedure SetstartDescentDistance(value: double); | |
procedure SetstopDescentDistance(value: double); | |
procedure SetxyzReadDelay(value: integer); | |
public | |
homePt, currentPos: TMManPt; | |
mmanCalibrationPts: array[0..3] of TMManPt; | |
xyzCalibrationPts: array[0..3] of TXYZPt; | |
xyzTargetPt: TXYZPt; | |
procedure Calibrate; | |
procedure ContactMoveDown(bDown: boolean); | |
procedure GetXYZ; virtual; {in microns} | |
procedure GetCurrentMMPosition; | |
procedure GoHome; | |
procedure GotoDescentPos; | |
procedure MoveAndWait(manPt: TMManPt); | |
procedure MoveToXYZ(newX, newY, newZ: double); virtual; | |
procedure MoveRelative(deltaX, deltaY, deltaZ: double); | |
procedure StartApproach; | |
procedure StartDescent; | |
constructor CreateManip(index: integer); | |
property approachAngle: double read GetApproachAngle write SetApproachAngle; | |
property approachSpeed: integer read GetApproachSpeed write SetApproachSpeed; | |
property axialIsXZ: boolean read GetAxialIsXZ write SetAxialIsXZ; | |
property calibrationShift: integer read GetCalibrationShift write SetCalibrationShift; | |
property Busy: boolean read fBusy; | |
property CoarseMotion: boolean read GetCoarseMotion write SetCoarseMotion; | |
property COMPort: integer read GetCOMPort write SetCOMPort; | |
property COMSpeed: integer read GetCOMSpeed write SetCOMSpeed; | |
property contactSpeed: integer read GetContactSpeed write SetContactSpeed; | |
property contactStepSize: double read GetContactStepSize write SetContactStepSize; | |
property descentSpeed: integer read GetDescentSpeed write SetDescentSpeed; | |
property InvertX: boolean read GetInvertX write SetInvertX; | |
property InvertY: boolean read GetInvertY write SetInvertY; | |
property InvertZ: boolean read GetInvertZ write SetInvertZ; | |
property firstMotionType: TMManCoordinates read GetFirstMotionType write SetFirstMotionType; | |
property mmReadDelay: integer read GetmmReadDelay write SetmmReadDelay; | |
property secondMotionType: TMManCoordinates read GetSecondMotionType write SetSecondMotionType; | |
property thirdMotionType: TMManCoordinates read GetThirdMotionType write SetThirdMotionType; | |
property Phase: TMManPhase read fMManPhase write fMManPhase; | |
property Speed: integer read fSpeed write SetSpeed; | |
property startDescentDistance: double read GetstartDescentDistance write SetstartDescentDistance; | |
property stopDescentDistance: double read GetstopDescentDistance write SetstopDescentDistance; | |
property xyzReadDelay: integer read GetxyzReadDelay write SetxyzReadDelay; | |
end; | |
TMP285MoveRec = packed record | |
case integer of | |
1: (command: Char; | |
x, y, z: integer); | |
2: (ss: array[0..12] of Char); | |
end; | |
TMP285SpeedRec = packed record | |
case integer of | |
1: (command: Char; | |
speed: int16); | |
2: (ss: array[0..2] of Char); | |
end; | |
TMP285 = class(TMicromanipulator) | |
private | |
microstepsPerMicron: double; | |
CRTriggerHandle, TimerHandle: Word; | |
serialPort: TApdCOMPort; | |
sserial: string; {strings sent back by the serial ports} | |
function GetCoarseMotion: boolean; override; | |
procedure SetCoarseMotion(value: boolean); override; | |
procedure SetSpeed(value: integer); override; | |
procedure TriggerData(CP: TObject; TriggerHandle: Word); | |
procedure TriggerAvail(CP: TObject; Count: Word); | |
procedure TimerReceived(CP: TObject; TriggerHandle: Word); | |
procedure UpdateMP285Display; | |
public | |
procedure Connect; override; | |
procedure GetXYZ; override; | |
procedure MoveToXYZ(newX, newY, newZ: double); override; | |
constructor CreateManip(index: integer); | |
destructor Destroy; override; | |
end; | |
{******************************** Laser Control *******************************} | |
TLaserControl = class(TMPScanDevice) | |
private | |
fWavelength : integer; | |
fPower: double; | |
function GetincA: double; | |
function GetincB: double; | |
function GetincC: double; | |
function GetincD: double; | |
function GetdecA: double; | |
function GetdecB: double; | |
function GetdecC: double; | |
function GetdecD: double; | |
function GetCOMPort: integer; | |
function GetCOMSpeed: integer; | |
procedure SetincA(value: double); | |
procedure SetincB(value: double); | |
procedure SetincC(value: double); | |
procedure SetincD(value: double); | |
procedure SetdecA(value: double); | |
procedure SetdecB(value: double); | |
procedure SetdecC(value: double); | |
procedure SetdecD(value: double); | |
procedure SetCOMPort(value: integer); | |
procedure SetCOMSpeed(value: integer); | |
procedure SetPower(newPower: double); virtual; | |
procedure SetWavelength(newWavelength: integer); virtual; | |
public | |
autoObject: IMPLaserControl; | |
constructor Create; | |
destructor Destroy; override; | |
{pulse width at GPCTR0 = f(LaserPower, A, B, C, D)} | |
property incA: double read GetincA write SetincA; | |
property incB: double read GetincB write SetincB; | |
property incC: double read GetincC write SetincC; | |
property incD: double read GetincD write SetincD; | |
property decA: double read GetdecA write SetdecA; | |
property decB: double read GetdecB write SetdecB; | |
property decC: double read GetdecC write SetdecC; | |
property decD: double read GetdecD write SetdecD; | |
property COMPort: integer read GetCOMPort write SetCOMPort; | |
property COMSpeed: integer read GetCOMSpeed write SetCOMSpeed; | |
property Power: double read fPower write SetPower; | |
property Wavelength: integer read fWavelength write SetWavelength; | |
end; | |
TKimZhangLaserControl = class(TLaserControl) | |
private | |
prevPower: integer; | |
procedure SetPower(newPower: double); override; | |
public | |
procedure Connect; override; | |
constructor Create; | |
end; | |
{*********************************** Z Piezo **********************************} | |
TZPiezo = class(TMPScanDevice) | |
private | |
fZPiezoRange: double; | |
public | |
procedure OnScanningStarts; virtual; | |
procedure OnScanningEnds; virtual; | |
function ValidateParams(fromZ, toZ, deltaZ: double): boolean; virtual; | |
procedure Connect; override; | |
constructor Create; | |
property ZPiezoRange: double read fZPiezoRange; | |
end; | |
{MIPOS 100 from PiezoJena: 100 microns displacement, 0..10V command} | |
TMIPOS100 = class(TZPiezo) | |
private | |
zPiezoValues: array of int16; {contains digital voltages for the ramp to move the piezo} | |
public | |
procedure OnScanningStarts; override; {outputs a ramp} | |
procedure OnScanningEnds; override; {at the end,put piezo back to original pos} | |
function ValidateParams(fromZ, toZ, deltaZ: double): boolean; override; | |
procedure Connect; override; | |
constructor Create; | |
end; | |
{PI PIFOC 725 from PiezoJena: 400 microns displacement, 0..10V command} | |
TPIFOC725 = class(TMIPOS100) | |
constructor Create; | |
end; | |
{ **************************************************************************** } | |
{*} {*} | |
{* GLOBAL DEVICE OBJECTS *} | |
{*} {*} | |
{ **************************************************************************** } | |
const | |
deviceState: array[dsNotInstalled..dsDetected] of string = | |
('Not Installed', 'Installed', 'Not Found', 'Detected'); | |
var | |
multifunctionBoard: TMultifunctionBoard; | |
analogOutputBoard: TAnalogOutputBoard; | |
opticsOutputBoard: TOpticsOutputBoard; | |
photonCountingBoard: TPhotonCountingBoard; | |
laserShutter: TLaserShutter; | |
XYTable: TXYTable; | |
ZStepper: TZStepper; | |
micromanipulators: array[1..2] of TMicromanipulator; | |
xydeviceType: HARD_XY_TABLE; {0: not installed; 1: NEAT 300; 2: MP-285; 3: EPS 300; 4: XPS; 5: GALIL} | |
zStepperDeviceType: HARD_Z_STEPPER; {0: not installed; 1: Earl's; 2: MP-285; 3: EPS 300; 4: XPS; 5: GALIL} | |
mmDeviceType: array[1..2] of integer;{0: not installed, 1: MP-285, 2: MP-385} | |
laserControlType: HARD_LASER_CONTROL; {0: not installed; 1: Kim and Zhang; 2: Kim and Zhang Mai_Tai_0; 3: Kim and Zhang Mai_Tai_1} | |
laserControl: TLaserControl; | |
zPiezo: TZPiezo; | |
zPiezoType, {0: not installed; 1: 100 um piezo, 2: 400 um piezo} | |
zPiezoOutChannel: integer; | |
XPS_IP, XPS_GroupName: string; | |
xps: TXPS; | |
dmc40: TDMC40; | |
procedure LoadConfigFromRegistry; | |
procedure LoadDeviceFromConfiguration; | |
procedure Reconnect; | |
procedure SaveDeviceConfigurations; | |
procedure DestroyDevices; | |
{ **************************************************************************** } | |
{*} {*} | |
{*} IMPLEMENTATION {*} | |
{*} {*} | |
{ **************************************************************************** } | |
uses Nidaq, Nidaqcns, Registry, IniFiles, Math, Forms, Dialogs,Mainfrm, | |
Graphics; | |
type | |
TMP285Config = packed record | |
flags, | |
udirx, | |
udiry, | |
udirz: byte; | |
roe_vari, | |
uoffset, | |
urange, | |
pulse, | |
uspeed: word; | |
indevice, | |
flags_2: byte; {bit 2(STEP_MODE) = 4; Set = 50 usteps / step, reset: 10 usteps/steps; 1 step = 2 um} | |
jumpspd, | |
highspd, | |
dead, | |
watch_dog, | |
step_div, | |
step_mul, | |
flip_pt, | |
flpcalc: word; | |
end; | |
{hidden object which TZMP285 and TXYMP285 delegate their call} | |
TXYZMP285 = class(TMPScanDevice) | |
microstepsPerMicron: double; {25: 0.04 microns per step; 5: 5 microns per step} | |
CRTriggerHandle, TimerHandle: Word; | |
serialPort: TApdCOMPort; | |
sserial: string; {strings sent back by the serial ports} | |
mmanOp: TMManOp; | |
procedure GetResolution; {sets microstepsPerMicron} | |
procedure TriggerData(CP: TObject; TriggerHandle: Word); | |
procedure TriggerAvail(CP: TObject; Count: Word); | |
procedure TimerReceived(CP: TObject; TriggerHandle: Word); | |
procedure SetSpeed(value: integer); | |
procedure UpdateMP285Display; | |
public | |
procedure Connect; override; | |
procedure GetXYZ; {synchronous; returns values in zStepper and XYTable} | |
procedure SetXYZ(newX, newY: integer; newZ: double); {in microns} | |
procedure SetXYZFast(newX, newY: integer; newZ: double); {in microns} | |
procedure XYCommand(const sCommand: string); | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
const | |
ESP300_XY_LIMIT = 1.0; | |
ESP300_Z_LIMIT = 0.1; | |
type | |
TESPMode = (ESP300_READY, ESP300_READING_X, ESP300_READING_Y,ESP300_READING_Z, | |
ESP300_MOVING_X, ESP300_MOVING_Y,ESP300_MOVING_Z, ESP300_COMMAND); | |
{hidden object which TZMP285 and TXYMP285 delegate their call} | |
TXYZESP300 = class(TMPScanDevice) | |
CRTriggerHandle, TimerHandle: Word; | |
serialPort: TApdCOMPort; | |
sserial: string; {strings sent back by the serial ports} | |
pX, pY, pZ: double; | |
lastX, lastY, lastZ, | |
maxVelocityX, maxVelocityY, maxVelocityZ: double; {in microns} | |
mmanOp: TMManOp; | |
fBusy, bMoveDone, bMovingError, bReading: boolean; | |
fESPMode: TESPMode; | |
procedure TriggerData(CP: TObject; TriggerHandle: Word); | |
procedure TriggerAvail(CP: TObject; Count: Word); | |
procedure TimerReceived(CP: TObject; TriggerHandle: Word); | |
procedure SetXYSpeed(speedIndex: integer); | |
procedure SetZSpeed(speedIndex: integer); | |
public | |
procedure Connect; override; | |
procedure GetZ(var newZ: double); | |
procedure MoveToRelativeZ(newDeltaZ: double); | |
procedure SetZ(var newZ: double); | |
procedure MoveToZ(newZ: double); | |
function ReadZ: double; | |
procedure ShiftByZ(deltaZ: double); | |
procedure GetXY(var newX, newY: integer); | |
procedure SetXY(var newX, newY: integer); | |
procedure SetRelativeXY(deltaX, deltaY: integer); | |
procedure MoveToXY(newX, newY: integer); | |
procedure ReadXY(var x, y: integer); | |
procedure ShiftByXY(deltaX, deltaY: integer); | |
procedure XYCommand(const sCommand: string); | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
{hidden object; XY and Z XPS objects delegate calls to this object} | |
const | |
{Registry entries} | |
sDevices = 'Devices'; | |
smultifunctionBoardIndex = 'multifunctionBoardIndex'; | |
sTTLTriggerLine = 'TTLTriggerLine'; | |
sanalogOutBoardIndex = 'analogOutBoardIndex'; | |
sOpticsOutBoardIndex = 'opticsOutBoardIndex'; | |
sPhotonCountingBoardIndex = 'PhotonCountingBoardIndex'; | |
sbAnalogOutBoardInstalled = 'bAnalogOutBoardInstalled'; | |
sbOpticsControlBoardInstalled = 'bOpticsControlBoardInstalled'; | |
sbPhotonCountingBoardInstalled = 'PhotonCountingBoardInstalled'; | |
sInvertPreamps = 'Invert Preamps'; | |
sbLogicLow = 'bLogicLow'; | |
sPMTOffsets: array[0..MAX_CH - 1] of string = ('PMT Offset 0', 'PMT Offset 1', 'PMT Offset 2', 'PMT Offset 3'); | |
sbAnalogOutBrdControlsShutter = 'bAnalogOutBrdControlsShutter'; | |
smultifuncBoardShutterIndex = 'multifuncBoardShutterIndex'; | |
sbCloseShutterAfterSection = 'bCloseShutterAfterSection'; | |
sshutterDelay = 'shutterDelay'; | |
sxydeviceType = 'xydeviceType'; | |
sxydeviceCOMPortIndex = 'xydeviceCOMPortIndex'; | |
sxydeviceCOMSpeedIndex = 'xydeviceCOMSpeedIndex'; | |
sxydeviceManualSpeed = 'xydeviceManualSpeed'; | |
sbxydeviceInvertX = 'bxydeviceInvertX'; | |
sbxydeviceInvertY = 'bxydeviceInvertY'; | |
szStepperDeviceType = 'zStepperDeviceType'; | |
szStepperCOMPort = 'z Stepper COM Port'; | |
szStepperCOMSpeed = 'z Stepper COM Speed'; | |
szStepperSpeed = 'z Stepper Stepping Speed'; | |
szStepperInvert = 'z Stepper Invert Motion'; | |
smmDeviceType : array[1..2] of string = ('mm1DeviceType', 'mm2DeviceType'); | |
smmCOMPortIndex: array[1..2] of string = ('mm1COMPortIndex', 'mm2COMPortIndex'); | |
smmCOMSpeedIndex: array[1..2] of string = ('mm1COMSpeedIndex', 'mm2COMSpeedIndex'); | |
smmInvertX: array[1..2] of string = ('bmm1InvertX', 'bmm2InvertX'); | |
smmInvertY: array[1..2] of string = ('bmm1InvertY', 'bmm2InvertY'); | |
smmInvertZ: array[1..2] of string = ('bmm1InvertZ', 'bmm2InvertZ'); | |
saxialIsXZs: array[1..2] of string = ('axialIsXZ1', 'axialIsXZ2'); | |
scalibrationShifts : array[1..2] of string = ('calibrationShift1','calibrationShift2'); | |
sapproachAngles : array[1..2] of string = ('approachAngle1','approachAngle2'); | |
sapproachSpeeds : array[1..2] of string = ('approachSpeed1','approachSpeed2'); | |
scontactSpeeds : array[1..2] of string = ('contactSpeed1','contactSpeed2'); | |
scontactStepSize : array[1..2] of string = ('contactStepSize1','contactStepSize2'); | |
sdescentSpeeds : array[1..2] of string = ('descentSpeed1','descentSpeed2'); | |
sstartDescentDistances : array[1..2] of string = ('startDescentDistance1','startDescentDistance2'); | |
sstopDescentDistances : array[1..2] of string = ('stopDescentDistance1','stopDescentDistance2'); | |
sfirstMotionTypes : array[1..2] of string = ('firstMotionType1','firstMotionType2'); | |
ssecondMotionTypes : array[1..2] of string = ('secondMotionType1','secondMotionType2'); | |
sthirdMotionTypes : array[1..2] of string = ('thirdMotionType1','thirdMotionType2'); | |
sT1Array: array[0..1] of string = ('T1_X', 'T1_Y'); | |
sT2Array: array[0..1] of string = ('T2_X', 'T2_Y'); | |
sDeltaTArray: array[0..1] of string = ('DeltaT_X', 'T1_Y'); | |
sLaserControlType = 'Laser Control Type'; | |
sLaserControlincA = 'Laser Control inc A'; | |
sLaserControlincB = 'Laser Control inc B'; | |
sLaserControlincC = 'Laser Control inc C'; | |
sLaserControlincD = 'Laser Control inc D'; | |
sLaserControldecA = 'Laser Control dec A'; | |
sLaserControldecB = 'Laser Control dec B'; | |
sLaserControldecC = 'Laser Control dec C'; | |
sLaserControldecD = 'Laser Control dec D'; | |
sLaserControlCOMPortIndex = 'Laser Control COM Port'; | |
sLaserControlCOMSpeedIndex = 'Laser Control COM Speed'; | |
sAnalogChNames: array[1..2] of string = ('AnalogChName1', 'AnalogChName2'); | |
sAnalogChPrefixes: array[1..2] of string = ('AnalogChPrefix1', 'AnalogChPrefix2'); | |
sAnalogChConvFactors: array[1..2] of string = ('AnalogChConvFactor1', 'AnalogChConvFactor2'); | |
sAnalogChUnits: array[1..2] of string = ('AnalogChUnit1', 'AnalogChUnit2'); | |
sAnalogChZeroOffsets: array[1..2] of string = ('AnalogChZeroOffset1', 'AnalogChZeroOffset2'); | |
sxyzReadDelay = 'xyzReadDelay'; | |
smmReadDelay = 'mmReadDelay'; | |
sZPiezoType = 'Z Piezo Type'; | |
sZPiezoOutChannel = 'Z Piezo output channel'; | |
sXPS_IP = 'XPS IP address'; | |
sXPS_GroupName = 'XPS group name'; | |
MAX_CLOSE_LOOP_ITERATIONS = 20; {for NEAT300 close loop positioning} | |
MICROSTEP_SIZE = 25; {for MP-285} | |
var | |
multifunctionBoardIndex, | |
analogOutBoardIndex, | |
opticsOutBoardIndex, | |
PhotonCountingBoardIndex, | |
TTLTriggerLine: integer; | |
bAnalogOutBoardInstalled, | |
bOpticsOutputBoardInstalled, | |
bPhotonCountingBoardInstalled, | |
bLogicLow: boolean; | |
PMTOffsetArray: array[0..MAX_CH - 1] of int16; | |
T1Array, T2Array, DeltaTArray: array[0..1] of integer; {feedforward mirror parameters} | |
bAnalogOutBrdControlsShutter: boolean; | |
multifuncBoardShutterIndex: integer; | |
bCloseShutterAfterSection: boolean; | |
shutterDelay: integer; {in ms} | |
invertPreamps: boolean; {12-11-07} | |
xydeviceCOMPortIndex, | |
xydeviceCOMSpeedIndex, | |
xydeviceManualSpeed: integer; {1 to 10} | |
bxydeviceInvertX, | |
bxydeviceInvertY: boolean; | |
zStepperCOMPort, {for future steppers using a COM port} | |
zStepperCOMSpeed, | |
zStepperSpeed: integer; | |
zStepperInvert: boolean; | |
xyzMP285: TXYZMP285; | |
xyzESP300: TXYZESP300; | |
fxyzReadDelay, fmmReadDelay: integer; {delays to read MP-285 after move} | |
bmmInvertX, bmmInvertY, bmmInvertZ: array[1..2] of boolean; | |
mmCOMPortIndex, | |
mmCOMSpeedIndex: array[1..2] of integer; | |
calibrationShifts: array[1..2] of integer; | |
approachSpeeds, | |
contactSpeeds, | |
descentSpeeds: array[1..2] of integer; | |
approachAngles, | |
contactStepSizes, | |
startDescentDistances, | |
stopDescentDistances: array[1..2] of double; | |
firstMotionTypes, | |
secondMotionTypes, | |
thirdMotionTypes: array[1..2] of TMManCoordinates; | |
axialIsXZs: array[1..2] of boolean; | |
laserControlincA, laserControlincB, laserControlincC, laserControlincD, | |
laserControldecA, laserControldecB, laserControldecC, laserControldecD: double; | |
laserControlCOMPortIndex, | |
laserControlCOMSpeedIndex: integer; | |
fAnalogChConvFactors: array[1..2] of double; | |
fAnalogChNames: array[1..2] of string; | |
fAnalogChPrefixes: array[1..2] of TPrefix; | |
fAnalogChUnits: array[1..2] of string; | |
fAnalogChZeroOffsets: array[1..2] of double; | |
outputChannels: array[0..3] of int16; | |
function FindDistance(pt1, pt2: TMManPt): double; | |
begin | |
Result := Sqrt(Sqr(pt1[mmanX] - pt2[mmanY]) + Sqr(pt1[mmanY] - pt2[mmanY]) | |
+ Sqr(pt1[mmanZ] - pt2[mmanZ])); | |
end; | |
procedure DestroyDevices; | |
begin | |
FreeAndNil(multifunctionBoard); | |
FreeAndNil(analogOutputBoard); | |
FreeAndNil(opticsOutputBoard); | |
FreeAndNil(laserShutter); | |
FreeAndNil(XYTable); | |
FreeAndNil(ZStepper); | |
FreeAndNil(micromanipulators[1]); | |
FreeAndNil(micromanipulators[2]); | |
FreeAndNil(laserControl); | |
FreeAndNil(zPiezo); | |
end; | |
procedure Reconnect; | |
begin | |
DestroyDevices; | |
{creates objects and sets properties} | |
multifunctionBoard := TMultifunctionBoard.Create; | |
analogOutputBoard := TAnalogOutputBoard.Create; | |
opticsOutputBoard := TOpticsOutputBoard.Create; | |
laserShutter := TLaserShutter.Create; | |
case xydeviceType of | |
XY_NEAT300: XYTable := TNEAT300.Create; | |
XY_MP285: XYTable := TXYMP285.Create; | |
XY_ESP300: XYTable := TXYESP300.Create; | |
XY_XPS: XYTable := TXY_XPS.Create; | |
XY_GALIL: XYTable := TXY_DMC40.Create; | |
else XYTable := TXYTable.Create; | |
end; | |
XYTable.Connect; | |
case zStepperDeviceType of | |
Z_EARL: zStepper := TEarlStepper.Create; | |
Z_MP285: zStepper := TZMP285.Create; | |
Z_ESP300: zStepper := TZESP300.Create; | |
Z_XPS: zStepper := TZ_XPS.Create; | |
Z_GALIL: zStepper := TZ_DMC40.Create; | |
else zStepper := TzStepper.Create; | |
end; | |
ZStepper.Connect; | |
case mmDeviceType[1] of | |
0: micromanipulators[1] := TMicromanipulator.CreateManip(1); | |
else micromanipulators[1] := TMP285.CreateManip(1); | |
end; | |
micromanipulators[1].Connect; | |
case mmDeviceType[2] of | |
0: micromanipulators[2] := TMicromanipulator.CreateManip(2); | |
else micromanipulators[2] := TMP285.CreateManip(2); | |
end; | |
micromanipulators[2].Connect; | |
case laserControlType of | |
LASER_NOT_INSTALLED: laserControl := TLaserControl.Create; | |
else laserControl := TKimZhangLaserControl.Create; | |
end; | |
laserControl.Connect; | |
case zPiezoType of | |
ZPIEZO_NONE: zPiezo := TZPiezo.Create; | |
ZPIEZO_MIPOS100: zPiezo := TMIPOS100.Create {ZPIEZO_MIPOS100}; | |
else zPiezo := TPIFOC725.Create; | |
end; | |
zPiezo.Connect; | |
end; | |
procedure LoadConfigFromRegistry; | |
var i: integer; | |
begin | |
with TRegistryIniFile.Create(sAppName) do | |
begin | |
multifunctionBoardIndex := ReadInteger(sDevices, smultifunctionBoardIndex, DEFAULT_DEVICE_INDEX); | |
analogOutBoardIndex := ReadInteger(sDevices, sanalogOutBoardIndex, DEFAULT_SHUTTER_DEVICE_INDEX); | |
opticsOutBoardIndex := ReadInteger(sDevices, sOpticsOutBoardIndex, DEFAULT_OPTICS_DEVICE_INDEX); | |
PhotonCountingBoardIndex := ReadInteger(sDevices, sPhotonCountingBoardIndex, DEFAULT_PHOTON_COUNTING_DEVICE_INDEX); | |
TTLTriggerLine := ReadInteger(sDevices, sTTLTriggerLine, 0); | |
bAnalogOutBoardInstalled := ReadBool(sDevices, sbAnalogOutBoardInstalled, True); | |
bOpticsOutputBoardInstalled := ReadBool(sDevices, sbOpticsControlBoardInstalled, False); | |
bPhotonCountingBoardInstalled := ReadBool(sDevices, sbPhotonCountingBoardInstalled, False); | |
InvertPreamps := ReadBool(sDevices, sInvertPreamps, False); | |
bLogicLow := ReadBool(sDevices, sbLogicLow, True); | |
bAnalogOutBrdControlsShutter := ReadBool(sDevices, sbAnalogOutBrdControlsShutter, True); | |
PMTOffsetArray[0] := int16(ReadInteger(sDevices, sPMTOffsets[0], 0)); | |
PMTOffsetArray[1] := int16(ReadInteger(sDevices, sPMTOffsets[1], 0)); | |
PMTOffsetArray[2] := int16(ReadInteger(sDevices, sPMTOffsets[2], 0)); | |
PMTOffsetArray[3] := int16(ReadInteger(sDevices, sPMTOffsets[3], 0)); | |
multifuncBoardShutterIndex := ReadInteger(sDevices, smultifuncBoardShutterIndex, 0); | |
bCloseShutterAfterSection := ReadBool(sDevices, sbCloseShutterAfterSection, True); | |
shutterDelay := ReadInteger(sDevices, sshutterDelay, 100); {100 ms} | |
xydeviceType := HARD_XY_TABLE(ReadInteger(sDevices, sxydeviceType, Ord(XY_NOT_INSTALLED))); {Not installed} | |
xydeviceCOMPortIndex := ReadInteger(sDevices, sxydeviceCOMPortIndex, 1); | |
xydeviceCOMSpeedIndex := ReadInteger(sDevices, sxydeviceCOMSpeedIndex, 9600); | |
bxydeviceInvertX := ReadBool(sDevices, sbxydeviceInvertX, True); | |
bxydeviceInvertY := ReadBool(sDevices, sbxydeviceInvertY, True); | |
xydeviceManualSpeed := ReadInteger(sDevices, sxydeviceManualSpeed, 2); | |
zStepperDeviceType := HARD_Z_STEPPER(ReadInteger(sDevices, szStepperDeviceType, Ord(Z_NOT_INSTALLED))); | |
zStepperCOMPort := ReadInteger(sDevices, szStepperCOMPort, 1); | |
zStepperCOMSpeed := ReadInteger(sDevices, szStepperCOMSpeed, 9600); | |
zStepperSpeed := ReadInteger(sDevices, szStepperSpeed, 1); | |
if zStepperSpeed < 1 then zStepperSpeed := 1; | |
if zStepperSpeed > 20 then zStepperSpeed := 20; | |
zStepperInvert := ReadBool(sDevices, szStepperInvert, False); | |
fxyzReadDelay := ReadInteger(sDevices, sxyzReadDelay, 2000); | |
fmmReadDelay := ReadInteger(sDevices, smmReadDelay, 2000); | |
for i := 1 to 2 do | |
begin | |
mmDeviceType[i] := ReadInteger(sDevices, smmDeviceType[i], 0); | |
mmCOMPortIndex[i] := ReadInteger(sDevices, smmCOMPortIndex[i], 1); | |
mmCOMSpeedIndex[i] := ReadInteger(sDevices, smmCOMSpeedIndex[i], 9600); | |
bmmInvertX[i] := ReadBool(sDevices, smmInvertX[i], False); | |
bmmInvertY[i] := ReadBool(sDevices, smmInvertY[i], False); | |
bmmInvertZ[i] := ReadBool(sDevices, smmInvertZ[i], False); | |
axialIsXZs[i] := ReadBool(sDevices, saxialIsXZs[i], False); | |
calibrationShifts[i] := ReadInteger(sDevices, scalibrationShifts[i], 100); {100 microns} | |
approachAngles[i] := ReadFloat(sDevices, sapproachAngles[i], 30); {30 degrees} | |
{try..finally for compatibility with prev versions of MPScan where speeds were floats} | |
try | |
approachSpeeds[i] := ReadInteger(sDevices, sapproachSpeeds[i], 1000); {1000 microns/s} | |
except | |
approachSpeeds[i] := Round(ReadFloat(sDevices, sapproachSpeeds[i], 1000)); {1000 microns/s} | |
end; | |
try | |
contactSpeeds[i] := ReadInteger(sDevices, scontactSpeeds[i], 1); {1 micron/s} | |
except | |
contactSpeeds[i] := Round(ReadFloat(sDevices, scontactSpeeds[i], 1)); {1 micron/s} | |
end; | |
try | |
descentSpeeds[i] := ReadInteger(sDevices, sdescentSpeeds[i], 10); {10 microns/s} | |
except | |
descentSpeeds[i] := Round(ReadFloat(sDevices, sdescentSpeeds[i], 10)); {10 microns/s} | |
end; | |
contactStepSizes[i] := ReadFloat(sDevices, scontactStepSize[i], 0.1); {0.1 micron} | |
startDescentDistances[i] := ReadFloat(sDevices, sstartDescentDistances[i], 200); | |
stopDescentDistances[i] := ReadFloat(sDevices, sstopDescentDistances[i], 5); | |
firstMotionTypes[i] := TMManCoordinates(ReadInteger(sDevices, sfirstMotionTypes[i], Ord(mmanZ))); | |
secondMotionTypes[i] := TMManCoordinates(ReadInteger(sDevices, ssecondMotionTypes[i], Ord(mmanY))); | |
thirdMotionTypes[i] := TMManCoordinates(ReadInteger(sDevices, sthirdMotionTypes[i], Ord(mmanX))); | |
{Analog outputs} | |
fAnalogChConvFactors[i] := ReadFloat(sDevices, sAnalogChConvFactors[i], 1); | |
fAnalogChNames[i] := ReadString(sDevices, sAnalogChNames[i], 'AO' + IntToStr(i-1)); | |
fAnalogChPrefixes[i] := TPrefix(ReadInteger(sDevices, sAnalogChPrefixes[i], Ord(tpUNITY))); | |
fAnalogChUnits[i] := ReadString(sDevices, sAnalogChUnits[i], 'V'); | |
fAnalogChZeroOffsets[i] := ReadFloat(sDevices, sAnalogChZeroOffsets[i], 0); | |
end; | |
for i := 0 to 1 do | |
begin | |
T1Array[i] := ReadInteger(sDevices, sT1Array[i], 0); | |
T2Array[i] := ReadInteger(sDevices, sT2Array[i], 0); | |
DeltaTArray[i] := ReadInteger(sDevices, sDeltaTArray[i], 0); | |
end; | |
laserControlType := HARD_LASER_CONTROL(ReadInteger(sDevices, sLaserControlType, 0)); | |
laserControlincA := ReadFloat(sDevices, sLaserControlincA, -0.5012); | |
laserControlincB := ReadFloat(sDevices, sLaserControlincB, 2.5569); | |
laserControlincC := ReadFloat(sDevices, sLaserControlincC, -2.6496); | |
laserControlincD := ReadFloat(sDevices, sLaserControlincD, 0.49916); | |
laserControldecA := ReadFloat(sDevices, sLaserControldecA, -0.50032); | |
laserControldecB := ReadFloat(sDevices, sLaserControldecB, 2.5467); | |
laserControldecC := ReadFloat(sDevices, sLaserControldecC, -2.582); | |
laserControldecD := ReadFloat(sDevices, sLaserControldecD, 0.49915); | |
laserControlComPortIndex := ReadInteger(sDevices, sLaserControlCOMPortIndex, 1); | |
laserControlComSpeedIndex := ReadInteger(sDevices, sLaserControlCOMSpeedIndex, 9600); | |
zPiezoType := ReadInteger(sDevices, sZPiezoType, ZPIEZO_NONE); | |
zPiezoOutChannel := ReadInteger(sDevices, sZPiezoOutChannel, 0); | |
XPS_IP := ReadString(sDevices, sXPS_IP, '192.168.0.50'); | |
XPS_GroupName := ReadString(sDevices, sXPS_GroupName, 'sample_stage'); | |
Free; | |
end; | |
end; | |
procedure SaveDeviceConfigurations; | |
var i: integer; | |
begin | |
with TRegistryIniFile.Create(sAppName) do | |
begin | |
WriteInteger(sDevices, smultifunctionBoardIndex, multifunctionBoardIndex); | |
WriteInteger(sDevices, sanalogOutBoardIndex, analogOutBoardIndex); | |
WriteInteger(sDevices, sOpticsOutBoardIndex, opticsOutBoardIndex); | |
WriteInteger(sDevices, sPhotonCountingBoardIndex, PhotonCountingBoardIndex); | |
WriteInteger(sDevices, sTTLTriggerLine, TTLTriggerLine); | |
WriteBool(sDevices, sbAnalogOutBoardInstalled, bAnalogOutBoardInstalled); | |
WriteBool(sDevices, sbOpticsControlBoardInstalled, bOpticsOutputBoardInstalled); | |
WriteBool(sDevices, sbPhotonCountingBoardInstalled, bPhotonCountingBoardInstalled); | |
WriteBool(sDevices, sbLogicLow, bLogicLow); | |
WriteBool(sDevices, sInvertPreamps, InvertPreamps); | |
WriteInteger(sDevices, sPMTOffsets[0], PMTOffsetArray[0]); | |
WriteInteger(sDevices, sPMTOffsets[1], PMTOffsetArray[1]); | |
WriteInteger(sDevices, sPMTOffsets[2], PMTOffsetArray[2]); | |
WriteInteger(sDevices, sPMTOffsets[3], PMTOffsetArray[3]); | |
WriteBool(sDevices, sbAnalogOutBrdControlsShutter, bAnalogOutBrdControlsShutter); | |
WriteInteger(sDevices, smultifuncBoardShutterIndex, multifuncBoardShutterIndex); | |
WriteBool(sDevices, sbCloseShutterAfterSection, bCloseShutterAfterSection); | |
WriteInteger(sDevices, sshutterDelay, shutterDelay); | |
WriteInteger(sDevices, sxydeviceType, Integer(xydeviceType)); {NEAT 300} | |
WriteInteger(sDevices, sxydeviceCOMPortIndex, xydeviceCOMPortIndex); | |
WriteInteger(sDevices, sxydeviceCOMSpeedIndex, xydeviceCOMSpeedIndex); | |
WriteBool(sDevices, sbxydeviceInvertX, bxydeviceInvertX); | |
WriteBool(sDevices, sbxydeviceInvertY, bxydeviceInvertY); | |
WriteInteger(sDevices, sxydeviceManualSpeed, xydeviceManualSpeed); | |
WriteInteger(sDevices, szStepperDeviceType, Integer(zStepperDeviceType)); | |
WriteInteger(sDevices, szStepperCOMPort, zStepperCOMPort); | |
WriteInteger(sDevices, szStepperCOMSpeed, zStepperCOMSpeed); | |
WriteInteger(sDevices, szStepperSpeed, zStepperSpeed); | |
WriteBool(sDevices, szStepperInvert, zStepperInvert); | |
WriteInteger(sDevices, sxyzReadDelay, fxyzReadDelay); | |
WriteInteger(sDevices, smmReadDelay, fmmReadDelay); | |
for i := 1 to 2 do | |
begin | |
WriteInteger(sDevices, smmDeviceType[i], mmDeviceType[i]); | |
WriteInteger(sDevices, smmCOMPortIndex[i], mmCOMPortIndex[i]); | |
WriteInteger(sDevices, smmCOMSpeedIndex[i], mmCOMSpeedIndex[i]); | |
WriteBool(sDevices, smmInvertX[i], bmmInvertX[i]); | |
WriteBool(sDevices, smmInvertY[i], bmmInvertY[i]); | |
WriteBool(sDevices, smmInvertZ[i], bmmInvertZ[i]); | |
WriteInteger(sDevices, scalibrationShifts[i], calibrationShifts[i]); | |
WriteFloat(sDevices, sapproachAngles[i], approachAngles[i]); | |
WriteInteger(sDevices, sapproachSpeeds[i], approachSpeeds[i]); | |
WriteInteger(sDevices, scontactSpeeds[i], contactSpeeds[i]); | |
WriteFloat(sDevices, scontactStepSize[i], contactStepSizes[i]); | |
WriteInteger(sDevices, sdescentSpeeds[i], descentSpeeds[i]); | |
WriteFloat(sDevices, sstartDescentDistances[i], startDescentDistances[i]); | |
WriteFloat(sDevices, sstopDescentDistances[i], stopDescentDistances[i]); | |
WriteInteger(sDevices, sfirstMotionTypes[i], Ord(firstMotionTypes[i])); | |
WriteInteger(sDevices, ssecondMotionTypes[i], Ord(secondMotionTypes[i])); | |
WriteInteger(sDevices, sthirdMotionTypes[i], Ord(thirdMotionTypes[i])); | |
WriteBool(sDevices, saxialIsXZs[i], axialIsXZs[i]); | |
{Analog outputs} | |
WriteFloat(sDevices, sAnalogChConvFactors[i], fAnalogChConvFactors[i]); | |
WriteString(sDevices, sAnalogChNames[i], fAnalogChNames[i]); | |
WriteInteger(sDevices, sAnalogChPrefixes[i], Ord(fAnalogChPrefixes[i])); | |
WriteString(sDevices, sAnalogChUnits[i], fAnalogChUnits[i]); | |
WriteFloat(sDevices, sAnalogChZeroOffsets[i], fAnalogChZeroOffsets[i]); | |
end; | |
for i := 0 to 1 do | |
begin | |
WriteInteger(sDevices, sT1Array[i], T1Array[i]); | |
WriteInteger(sDevices, sT2Array[i], T2Array[i]); | |
WriteInteger(sDevices, sDeltaTArray[i], DeltaTArray[i]); | |
end; | |
WriteInteger(sDevices, sLaserControlType, Ord(laserControlType)); | |
WriteFloat(sDevices, sLaserControlincA, laserControlincA); | |
WriteFloat(sDevices, sLaserControlincB, laserControlincB); | |
WriteFloat(sDevices, sLaserControlincC, laserControlincC); | |
WriteFloat(sDevices, sLaserControlincD, laserControlincD); | |
WriteFloat(sDevices, sLaserControldecA, laserControldecA); | |
WriteFloat(sDevices, sLaserControldecB, laserControldecB); | |
WriteFloat(sDevices, sLaserControldecC, laserControldecC); | |
WriteFloat(sDevices, sLaserControldecD, laserControldecD); | |
WriteInteger(sDevices, sLaserControlCOMPortIndex, laserControlComPortIndex); | |
WriteInteger(sDevices, sLaserControlCOMSpeedIndex, laserControlComSpeedIndex); | |
WriteInteger(sDevices, sZPiezoType, zPiezoType); | |
WriteInteger(sDevices, sZPiezoOutChannel, zPiezoOutChannel); | |
WriteString(sDevices, sXPS_IP, XPS_IP); | |
WriteString(sDevices, sXPS_GroupName, XPS_GroupName); | |
Free; | |
end; | |
end; | |
procedure LoadDeviceFromConfiguration; | |
begin | |
{Loads registry values} | |
LoadConfigFromRegistry; | |
{creates objects and sets properties} | |
multifunctionBoard := TMultifunctionBoard.Create; | |
analogOutputBoard := TAnalogOutputBoard.Create; | |
opticsOutputBoard := TOpticsOutputBoard.Create; | |
photonCountingBoard := TPhotonCountingBoard.Create; | |
laserShutter := TLaserShutter.Create; | |
case xydeviceType of | |
XY_NEAT300: XYTable := TNEAT300.Create; | |
XY_MP285: XYTable := TXYMP285.Create; | |
XY_ESP300: XYTable := TXYESP300.Create; | |
XY_XPS: XYTable := TXY_XPS.Create; | |
XY_Galil: XYTable := TXY_DMC40.Create; | |
else XYTable := TXYTable.Create; | |
end; | |
case zStepperDeviceType of | |
Z_EARL: zStepper := TEarlStepper.Create; | |
Z_MP285: zStepper := TZMP285.Create; | |
Z_ESP300: zStepper := TZESP300.Create; | |
Z_XPS: zStepper := TZ_XPS.Create; | |
Z_Galil: zStepper := TZ_DMC40.Create; | |
else zStepper := TzStepper.Create; | |
end; | |
case mmDeviceType[1] of | |
0: micromanipulators[1] := TMicromanipulator.CreateManip(1); | |
else micromanipulators[1] := TMP285.CreateManip(1); | |
end; | |
case mmDeviceType[2] of | |
0: micromanipulators[2] := TMicromanipulator.CreateManip(2); | |
else micromanipulators[2] := TMP285.CreateManip(2); | |
end; | |
case laserControlType of | |
LASER_NOT_INSTALLED: laserControl := TLaserControl.Create; | |
else laserControl := TKimZhangLaserControl.Create; | |
end; | |
case zPiezoType of | |
ZPIEZO_NONE: zPiezo := TZPiezo.Create; | |
ZPIEZO_MIPOS100: zPiezo := TMIPOS100.Create {ZPIEZO_MIPOS100}; | |
else zPiezo := TPIFOC725.Create; | |
end; | |
end; | |
function TMPScanDevice.GetDeviceState: TDeviceState; | |
begin | |
Result := fDeviceState; | |
end; | |
procedure TMPScanDevice.Connect; | |
begin | |
fDeviceState := dsNotInstalled; | |
end; | |
{********************************* TXYZMP285 ***********************************} | |
// | |
// Resolution of MP-285 is 5 microsteps /microns => 0.2 um / step by default | |
// | |
procedure TXYZMP285.GetResolution; | |
var MP285Config: TMP285Config; | |
begin | |
mmanOp := mmanGetResolution; | |
sserial := ''; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
{06-23-06; Sutter MP-285 serial port leaves garbage; this cleans it} | |
PurgeComm(serialPort.Dispatcher.Handle, PURGE_RXCLEAR); | |
serialPort.PutString('s' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until mmanOp = mmanOK; | |
Move(sserial[1], MP285Config, SizeOf(MP285Config)); | |
if MP285Config.step_div > 32767 then {high-order bit of step_div is set} | |
microstepsPerMicron := 25 | |
else | |
microstepsPerMicron := 5; | |
end; | |
procedure TXYZMP285.TriggerData(CP: TObject; TriggerHandle: Word); | |
var newPos: array[0..2] of integer; | |
i: integer; | |
begin | |
serialPort.SetTimerTrigger(TimerHandle, 256, False); | |
if TriggerHandle <> CRTriggerHandle then Exit; | |
if mmanOp = mmanOK then Exit; {because TriggerData is called for the last CR} | |
case mmanOp of | |
mmanGetPos, mmanGetPosAndWait: | |
begin | |
if Length(sserial) >= SizeOf(newPos) then | |
begin | |
{copy return string} | |
Move(sserial[1], newPos, SizeOf(newPos)); | |
{convert microsteps into microns} // | |
// X, Y are integers , while Z is settled as continuous one | |
xyTable.fXPosition := Round(newPos[0] / MICROSTEP_SIZE); | |
xyTable.fYPosition := Round(newPos[1] / MICROSTEP_SIZE); | |
zStepper.fZPosition := newPos[2] / MICROSTEP_SIZE; | |
end; | |
if mmanOp = mmanGetPos then | |
begin | |
Mainform.UpdateXYCaptions; | |
Mainform.UpdateZCaptions; | |
end; | |
end; | |
{mmanSetSpeed: no need to process: there is no acknowledgment} | |
mmanMove: | |
begin | |
{MP-285 is a slow device - this loop adds a delay after a move} | |
for i := 1 to fxyzReadDelay do Application.ProcessMessages; | |
xyTable.OnMoveFinished; {updates the captions} | |
zStepper.OnMoveFinished; | |
end; | |
end; | |
xyTable.fBusy := False; | |
if zStepper <> nil then zStepper.fBusy := False; | |
sSerial := ''; | |
mmanOp := mmanOK; | |
end; | |
procedure TXYZMP285.TriggerAvail(CP: TObject; Count: Word); | |
var i: Word; | |
begin | |
for i := 1 to Count do | |
sserial := sserial + serialPort.GetChar; | |
end; | |
procedure TXYZMP285.TimerReceived(CP: TObject; TriggerHandle: Word); | |
begin | |
if TriggerHandle = TimerHandle then | |
begin | |
{time-out: we lost the device} | |
fDeviceState := dsNotFound; | |
xyTable.fBusy := False; | |
if zStepper <> nil then zStepper.fBusy := False; | |
mmanOp := mmanOK; | |
end; | |
end; | |
procedure TXYZMP285.SetSpeed(value: integer); {1: slowest, 20: fastest} | |
var s: string; | |
speedRecord : TMP285SpeedRec; | |
begin | |
if mmanOp <> mmanOK then Exit; | |
speedRecord.command := 'v'; | |
{always low resolution: speed limited to 2900 microns/s} | |
speedRecord.speed := Muldiv(2900, value, 20); | |
SetLength(s, SizeOf(TMP285SpeedRec)); | |
Move(speedRecord, s[1], SizeOf(TMP285SpeedRec)); | |
mmanOp := mmanSetSpeed; | |
sserial := ''; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
{06-23-06; Sutter MP-285 serial port leaves garbage; this cleans it} | |
PurgeComm(serialPort.Dispatcher.Handle, PURGE_RXCLEAR); | |
serialPort.PutString(s + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until mmanOp = mmanOK; | |
end; | |
procedure TXYZMP285.UpdateMP285Display; | |
begin | |
mmanOp := mmanUpdateDisplay; | |
sserial := ''; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('n' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until mmanOp = mmanOK; | |
end; | |
procedure TXYZMP285.Connect; | |
begin | |
if deviceStatus = dsDetected then Exit; | |
inherited Connect; | |
try | |
with serialPort do | |
begin | |
Baud := XYTable.COMSpeed; | |
COMNumber := XYTable.COMPort; | |
Parity := pNone; | |
DataBits := 8; | |
StopBits := 1; | |
serialPort.Open := True; | |
CRTriggerHandle := AddDataTrigger(Chr(13), False); | |
TimerHandle := AddTimerTrigger; | |
OnTriggerData := TriggerData; | |
OnTriggerAvail := TriggerAvail; | |
OnTriggerTimer := TimerReceived; | |
end; | |
mmanOp := mmanOK; | |
try | |
fDeviceState := dsDetected; | |
{ GetResolution; DEBUG} | |
except | |
fDeviceState := dsNotFound; | |
end; | |
except | |
fDeviceState := dsNotFound; | |
end; | |
mmanOp := mmanOK; | |
end; | |
procedure TXYZMP285.GetXYZ; | |
begin | |
if mmanOp <> mmanOK then Exit; | |
sserial := ''; | |
mmanOp := mmanGetPosAndWait; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
{06-23-06; Sutter MP-285 serial port leaves garbage; this cleans it} | |
PurgeComm(serialPort.Dispatcher.Handle, PURGE_RXCLEAR); | |
serialPort.PutString('c' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until mmanOp <> mmanGetPosAndWait; | |
end; | |
procedure TXYZMP285.SetXYZ(newX, newY: integer; newZ: double); | |
var moverecord: TMP285MoveRec; | |
s: string; | |
begin | |
if mmanOp <> mmanOK then Exit; | |
{converts microns to microsteps} | |
with moverecord do | |
begin | |
command := 'm'; | |
x := newX * MICROSTEP_SIZE; {one microstep = 0.2 microns or 0.04} | |
y := newY * MICROSTEP_SIZE; | |
z := Round(newZ * MICROSTEP_SIZE); | |
end; | |
SetLength(s, SizeOf(TMP285MoveRec)); | |
Move(moverecord, s[1], SizeOf(TMP285MoveRec)); | |
sserial := ''; | |
mmanOp := mmanMove; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString(s + Chr(13)); {go for it} | |
end; | |
procedure TXYZMP285.SetXYZFast(newX, newY: integer; newZ: double); | |
var moverecord: TMP285MoveRec; | |
s: string; | |
begin | |
if mmanOp <> mmanOK then Exit; | |
{converts microns to microsteps} | |
with moverecord do | |
begin | |
command := 'm'; | |
x := newX * MICROSTEP_SIZE; {one microstep = 0.2 microns} | |
y := newY * MICROSTEP_SIZE; | |
z := Round(newZ * MICROSTEP_SIZE); | |
end; | |
SetLength(s, SizeOf(TMP285MoveRec)); | |
Move(moverecord, s[1], SizeOf(TMP285MoveRec)); | |
sserial := ''; | |
mmanOp := mmanMoveFast; {no callback} | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString(s + Chr(13)); {go for it} | |
end; | |
procedure TXYZMP285.XYCommand(const sCommand: string); | |
begin | |
if mmanOp <> mmanOK then Exit; | |
sserial := ''; | |
mmanOp := mmanCommand; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
{06-23-06; Sutter MP-285 serial port leaves garbage; this cleans it} | |
PurgeComm(serialPort.Dispatcher.Handle, PURGE_RXCLEAR); | |
serialPort.PutString(sCommand + Chr(13)); {go for it} | |
repeat | |
Application.ProcessMessages; | |
until mmanOp = mmanOK; | |
end; | |
constructor TXYZMP285.Create; | |
begin | |
inherited Create; | |
microstepsPerMicron := 5; | |
serialPort := TApdCOMPort.Create(nil); | |
serialPort.AutoOpen := False; | |
end; | |
destructor TXYZMP285.Destroy; | |
begin | |
serialPort.Free; | |
inherited Destroy; | |
end; | |
{******************************* NI-DAQ Board *********************************} | |
{procedure TNIDAQBoard.SetDeviceState(newState: TDeviceState); override; | |
begin | |
if newState <> dsNotInstalled then Connect else fDeviceState := newState; | |
end;} | |
function TNIDAQBoard.GetBoardIndex: integer; | |
begin | |
Result := 0; | |
end; | |
procedure TNIDAQBoard.SetBoardIndex(newIndex: integer); | |
begin | |
end; | |
procedure TNIDAQBoard.SetDigitalPort(dioValue: integer); | |
begin | |
if fDeviceState = dsDetected then | |
begin | |
if fbLogicLow then dioValue := not dioValue; | |
DIG_Out_Prt(BoardIndex, PORT_0, dioValue); | |
end; | |
fDigitalPort := dioValue; | |
end; | |
procedure TNIDAQBoard.SetDigitalBit(bitIndex: integer; value: boolean); {takes into account logic} | |
var mask: integer; | |
ivalue: Smallint; | |
begin | |
mask := 1 shl bitIndex; | |
if value then | |
fDigitalPort := fDigitalPort or mask | |
else | |
fDigitalPort := fDigitalPort and (not mask); | |
if fbLogicLow then value := not value; | |
if value then ivalue := 1 else ivalue := 0; | |
DIG_Out_Line(BoardIndex, PORT_0, bitIndex, ivalue); | |
end; | |
{**************************** TMultifunctionBoard *****************************} | |
function TMultifunctionBoard.GetInvertPreamps: boolean; | |
begin | |
Result := InvertPreamps; | |
end; | |
function TMultifunctionBoard.GetBoardIndex: integer; | |
begin | |
Result := multifunctionBoardIndex; | |
end; | |
function TMultifunctionBoard.GetLogicLow: boolean; | |
begin | |
Result := bLogicLow; | |
end; | |
{returns the resolution of the analog out channels} | |
function TMultifunctionBoard.GetMaxAnalogOutDigitalValue: integer; | |
begin | |
if (name = sPCI_6110E) then Result := 32768 else Result := 2048; | |
end; | |
function TMultifunctionBoard.GetPMTOffsets(chIndex: integer): int16; | |
begin | |
if (chIndex >= 0) and (chIndex <= 3) then | |
Result := PMTOffsetArray[chIndex] | |
else | |
Result := 0; | |
end; | |
function TMultifunctionBoard.GetTriggerLine: integer; | |
begin | |
case TTLTriggerPFILine of | |
0: Result := ND_PFI_0; | |
1: Result := ND_PFI_1; | |
2: Result := ND_PFI_2; | |
3: Result := ND_PFI_3; | |
4: Result := ND_PFI_4; | |
5: Result := ND_PFI_5; | |
6: Result := ND_PFI_6; | |
7: Result := ND_PFI_7; | |
8: Result := ND_PFI_8; | |
9: Result := ND_PFI_9; | |
else | |
Result := ND_PFI_0; | |
end; | |
end; | |
function TMultifunctionBoard.GetTTLTriggerPFILine: integer; | |
begin | |
Result := TTLTriggerLine; | |
end; | |
procedure TMultifunctionBoard.SetInvertPreamps(value: boolean); | |
begin | |
InvertPreamps := value; | |
end; | |
procedure TMultifunctionBoard.SetLogicLow(value: boolean); | |
begin | |
bLogicLow := value; | |
end; | |
procedure TMultifunctionBoard.SetTTLTriggerPFILine(lineIndex: integer); | |
begin | |
TTLTriggerLine := lineIndex; | |
end; | |
procedure TMultifunctionBoard.SetPMTOffsets(chIndex: integer; value: int16); | |
begin | |
PMTOffsetArray[chIndex] := value; | |
end; | |
procedure TMultifunctionBoard.Connect; | |
var dummy: array[0..1] of int16; | |
begin | |
if Init_DA_Brds(BoardIndex, @deviceCode) <> 0 then | |
fDeviceState := dsNotInstalled | |
else if (deviceCode = PCI_6110E) or (deviceCode = PCI_6115E) or (deviceCode = PXI_6115E) then | |
begin | |
if deviceCode = PCI_6115E then name := sPCI_6115E; | |
if deviceCode = PXI_6115E then name := sPXI_6115E; | |
fDeviceState := dsDetected; | |
dummy[0] := 0; dummy[1] := 1; | |
{------------------------ Configure Digital out ------------------------} | |
DIG_Prt_Config(BoardIndex, PORT_0, NO_HANDSHAKING, DIGITAL_OUTPUT); | |
{------------------------ Configure Analog in ------------------------} | |
Timeout_Config (BoardIndex, INFINITE_TIMEOUT {2 = Maximal timeout allowed <> INFINITE_TIMEOUT}); | |
AI_Configure (BoardIndex, ALL_CHANNELS, DIFFENTIAL, 10, BIPOLAR, driveAIS); | |
{------------------------ Configure Analog out ------------------------} | |
AO_Configure(BoardIndex, AO0, BIPOLAR_OUT, INTERNAL_REF, REF_VOLTAGE, UPDATE_WHEN_WRITTEN); | |
AO_Configure(BoardIndex, AO1, BIPOLAR_OUT, INTERNAL_REF, REF_VOLTAGE, UPDATE_WHEN_WRITTEN); | |
AO_Configure(BoardIndex, AO2, BIPOLAR_OUT, INTERNAL_REF, REF_VOLTAGE, UPDATE_WHEN_WRITTEN); | |
AO_Configure(BoardIndex, AO3, BIPOLAR_OUT, INTERNAL_REF, REF_VOLTAGE, UPDATE_WHEN_WRITTEN); | |
WFM_DB_Config(BoardIndex, 2, @dummy, DISABLE_DOUBLE_BUFFERING, 0, 0); | |
{DMA transfer: as many samples in FIFO as possible} | |
AO_Change_Parameter(BoardIndex, ALL_CHANNELS, ND_DATA_TRANSFER_CONDITION, ND_FIFO_HALF_FULL_OR_LESS_UNTIL_FULL); | |
{No interrupts} | |
AO_Change_Parameter(BoardIndex, ALL_CHANNELS, ND_LINK_COMPLETE_INTERRUPTS, ND_OFF); | |
{ Set_DAQ_Device_Info (deviceIndex, ND_AI_FIFO_INTERRUPTS , ND_INTERRUPT_HALF_FIFO);} | |
{------------------------ Configure RTSI signals ------------------------} | |
{Sets source of GPCTR0 to 20 MHz} | |
GPCTR_Change_Parameter(BoardIndex, ND_COUNTER_0, ND_SOURCE, ND_INTERNAL_20_MHZ); | |
{Puts 20 MHz clock on RTSI_0} | |
Select_Signal(BoardIndex, ND_RTSI_0, ND_GPCTR0_SOURCE, ND_LOW_TO_HIGH); | |
{Puts start of acquisition on RTSI_1} | |
Select_Signal(BoardIndex, ND_RTSI_1, ND_IN_SCAN_START, ND_LOW_TO_HIGH); | |
{----------------- Photon counting -------------------} | |
{Puts conversion signal on RTSI_2} | |
Select_Signal(BoardIndex, ND_RTSI_2, ND_IN_CONVERT, ND_HIGH_TO_LOW); | |
{Puts scan in progress signal on RTSI_3: precedes conversion} | |
// Select_Signal(BoardIndex, ND_RTSI_3, ND_IN_SCAN_IN_PROG, ND_LOW_TO_HIGH); | |
{Puts scan clock on RTSI 4: goes low after conversion} | |
// Select_Signal(BoardIndex, RTSI_4, ND_SCANCLK, ND_LOW_TO_HIGH); | |
end | |
else | |
fDeviceState := dsNotInstalled; | |
end; | |
function TMultifunctionBoard.GetT1(mirror: integer): integer; | |
begin | |
Result := T1Array[mirror]; | |
end; | |
function TMultifunctionBoard.GetT2(mirror: integer): integer; | |
begin | |
Result := T2Array[mirror]; | |
end; | |
function TMultifunctionBoard.GetDeltaT(mirror: integer): integer; | |
begin | |
Result := DeltaTArray[mirror]; | |
end; | |
procedure TMultifunctionBoard.SetBoardIndex(newIndex: integer); | |
begin | |
multifunctionBoardIndex := newIndex; | |
end; | |
procedure TMultifunctionBoard.SetT1(mirror: integer; value: integer); | |
begin | |
T1Array[mirror] := value; | |
end; | |
procedure TMultifunctionBoard.SetT2(mirror: integer; value: integer); | |
begin | |
T2Array[mirror] := value; | |
end; | |
procedure TMultifunctionBoard.SetDeltaT(mirror: integer; value: integer); | |
begin | |
DeltaTArray[mirror] := value; | |
end; | |
constructor TMultifunctionBoard.Create; | |
begin | |
name := sPCI_6110E; | |
Connect; | |
end; | |
{***************************** TAnalogOutputBoard *****************************} | |
procedure TAnalogOutputBoard.AllocateStimBuffer; | |
begin | |
DestroyStimBuffer; | |
cStimBufferSize := GetTotalSampleCount(analogStimParams); | |
GetMem(pStimBuffer, cStimBufferSize * SizeOf(int16)); | |
end; | |
function TAnalogOutputBoard.AnalogToDigital(chIndex: integer; value: double): int16; | |
begin | |
try | |
with analogStimParams do | |
{10 V = 2048 } | |
Result := Round(2048 * (value - chOffsets[chIndex]) / chConvFactors[chIndex] / OutputRange); | |
except | |
MessageDlg('Invalid analog value.', mtError, [mbOK], 0); | |
Result := 0; | |
end; | |
end; | |
procedure TAnalogOutputBoard.DestroyStimBuffer; | |
begin | |
if cStimBufferSize > 0 then | |
begin | |
FreeMem(pStimBuffer, cStimBufferSize * SizeOf(int16)); | |
cStimBufferSize := 0; | |
end; | |
end; | |
function TAnalogOutputBoard.GetAnalogChConvFactors(chIndex: integer): double; | |
begin | |
Result := fAnalogChConvFactors[chIndex]; | |
end; | |
function TAnalogOutputBoard.GetAnalogChNames(chIndex: integer): string; | |
begin | |
Result := fAnalogChNames[chIndex]; | |
end; | |
function TAnalogOutputBoard.GetAnalogChPrefixes(chIndex: integer): TPrefix; | |
begin | |
Result := fAnalogChPrefixes[chIndex]; | |
end; | |
function TAnalogOutputBoard.GetAnalogChUnits(chIndex: integer): string; | |
begin | |
Result := fAnalogChUnits[chIndex]; | |
end; | |
function TAnalogOutputBoard.GetAnalogChZeroOffset(chIndex: integer): double; | |
begin | |
Result := fAnalogChZeroOffsets[chIndex]; | |
end; | |
function TAnalogOutputBoard.GetBoardIndex: integer; | |
begin | |
Result := analogOutBoardIndex; | |
end; | |
function TAnalogOutputBoard.GetInstalled: boolean; | |
begin | |
Result := bAnalogOutBoardInstalled; | |
end; | |
function TAnalogOutputBoard.GetTotalSampleCount(const newParams: TAnalogStimRec): integer; | |
var n, i: integer; | |
cTotalSamples: array[1..2] of integer; | |
sampleRate: double; | |
begin | |
cTotalSamples[1] := 0; | |
cTotalSamples[2] := 0; | |
with newParams do | |
begin | |
case updateRateIndex of | |
0: sampleRate := 0.01; | |
1: sampleRate := 0.1; | |
2: sampleRate := 1; | |
3: sampleRate := 10; | |
else sampleRate := 1; | |
end; | |
try | |
for i := 1 to 2 do | |
if bChsEnabled[i] then | |
begin | |
cTotalSamples[i] := cTotalSamples[i] + Round(durations1[i] / sampleRate); | |
n := Round(durations2[i] / sampleRate) + Round(durations3[i] / sampleRate); | |
if stimTypes[i] = Ord(stTrain) then n := n * trainRepeats[i]; | |
cTotalSamples[i] := cTotalSamples[i] + n; | |
end; | |
if bChsEnabled[1] and bChsEnabled[2] then | |
begin | |
if cTotalSamples[1] >= cTotalSamples[2] then | |
Result := 2 * cTotalSamples[1] | |
else | |
Result := 2 * cTotalSamples[2]; | |
end | |
else if bChsEnabled[1] then | |
Result := cTotalSamples[1] | |
else | |
Result := cTotalSamples[2]; | |
except | |
Result := -1; | |
end; | |
end; | |
end; | |
procedure TAnalogOutputBoard.ReloadStimParams; | |
type TSamplePair = array[1..2] of int16; | |
TFramePair = array[0..MaxInt div 8] of TSamplePair; | |
TpFramePair = ^TFramePair; | |
var cSamples, i, j, cSamplesInSegment, chIndex: integer; | |
lastValues: array[1..2] of int16; | |
cSamplesInBuffer: array[1..2] of integer; | |
b2Channels: boolean; | |
clockRate: double; | |
begin | |
cSamples := GetTotalSampleCount(analogStimParams); | |
with analogStimParams do | |
begin | |
b2Channels := bChsEnabled[1] and bChsEnabled[2]; | |
if b2Channels then cSamples := cSamples div 2; | |
case updateRateIndex of | |
0: clockRate := 0.01; | |
1: clockRate := 0.1; | |
2: clockRate := 1; | |
3: clockRate := 10; | |
else clockRate := 1; | |
end; | |
for chIndex := 1 to 2 do | |
begin | |
cSamplesInBuffer[chIndex] := 0; | |
case stimTypes[chIndex] of | |
0: {Seal} | |
begin | |
{First level} | |
cSamplesInSegment := Round(durations1[chIndex]/clockRate); | |
lastValues[chIndex] := AnalogToDigital(chIndex, amplitude1[chIndex]); | |
if not b2Channels then | |
for i := 0 to cSamplesInSegment - 1 do | |
pStimBuffer^[i + cSamplesInBuffer[chIndex]] := lastValues[chIndex] | |
else | |
for i := 0 to cSamplesInSegment - 1 do | |
TpFramePair(pStimBuffer)^[i + cSamplesInBuffer[chIndex]][chIndex] | |
:= lastValues[chIndex]; | |
cSamplesInBuffer[chIndex] := cSamplesInBuffer[chIndex] + cSamplesInSegment; | |
{second level} | |
cSamplesInSegment := Round(durations2[chIndex]/clockRate); | |
lastValues[chIndex] := AnalogToDigital(chIndex, amplitude2[chIndex]); | |
if not b2Channels then | |
for i := 0 to cSamplesInSegment - 1 do | |
pStimBuffer^[i + cSamplesInBuffer[chIndex]] := lastValues[chIndex] | |
else | |
for i := 0 to cSamplesInSegment - 1 do | |
TpFramePair(pStimBuffer)^[i + cSamplesInBuffer[chIndex]][chIndex] | |
:= lastValues[chIndex]; | |
cSamplesInBuffer[chIndex] := cSamplesInBuffer[chIndex] + cSamplesInSegment; | |
end; | |
1: {Train} | |
begin | |
{First level} | |
cSamplesInSegment := Round(durations1[chIndex]/clockRate); | |
lastValues[chIndex] := AnalogToDigital(chIndex, amplitude1[chIndex]); | |
if not b2Channels then | |
for i := 0 to cSamplesInSegment - 1 do | |
pStimBuffer^[i + cSamplesInBuffer[chIndex]] := lastValues[chIndex] | |
else | |
for i := 0 to cSamplesInSegment - 1 do | |
TpFramePair(pStimBuffer)^[i + cSamplesInBuffer[chIndex]][chIndex] | |
:= lastValues[chIndex]; | |
cSamplesInBuffer[chIndex] := cSamplesInBuffer[chIndex] + cSamplesInSegment; | |
{second and third levels, repeated trainRepeats time} | |
for j := 0 to trainRepeats[chIndex] - 1 do | |
begin | |
{second level} | |
cSamplesInSegment := Round(durations2[chIndex]/clockRate); | |
lastValues[chIndex] := AnalogToDigital(chIndex, amplitude2[chIndex]); | |
if not b2Channels then | |
for i := 0 to cSamplesInSegment - 1 do | |
pStimBuffer^[i + cSamplesInBuffer[chIndex]] := lastValues[chIndex] | |
else | |
for i := 0 to cSamplesInSegment - 1 do | |
TpFramePair(pStimBuffer)^[i + cSamplesInBuffer[chIndex]][chIndex] | |
:= lastValues[chIndex]; | |
cSamplesInBuffer[chIndex] := cSamplesInBuffer[chIndex] + cSamplesInSegment; | |
{third level} | |
cSamplesInSegment := Round(durations3[chIndex]/clockRate); | |
lastValues[chIndex] := AnalogToDigital(chIndex, amplitude3[chIndex]); | |
if not b2Channels then | |
for i := 0 to cSamplesInSegment - 1 do | |
pStimBuffer^[i + cSamplesInBuffer[chIndex]] := lastValues[chIndex] | |
else | |
for i := 0 to cSamplesInSegment - 1 do | |
TpFramePair(pStimBuffer)^[i + cSamplesInBuffer[chIndex]][chIndex] | |
:= lastValues[chIndex]; | |
cSamplesInBuffer[chIndex] := cSamplesInBuffer[chIndex] + cSamplesInSegment; | |
end; {end j} | |
end; | |
2: {Incremental} | |
begin | |
{First level} | |
cSamplesInSegment := Round(durations1[chIndex]/clockRate); | |
lastValues[chIndex] := AnalogToDigital(chIndex, amplitude1[chIndex]); | |
if not b2Channels then | |
for i := 0 to cSamplesInSegment - 1 do | |
pStimBuffer^[i + cSamplesInBuffer[chIndex]] := lastValues[chIndex] | |
else | |
for i := 0 to cSamplesInSegment - 1 do | |
TpFramePair(pStimBuffer)^[i + cSamplesInBuffer[chIndex]][chIndex] | |
:= lastValues[chIndex]; | |
cSamplesInBuffer[chIndex] := cSamplesInBuffer[chIndex] + cSamplesInSegment; | |
{second level: amplitude is curamplitudes } | |
cSamplesInSegment := Round(durations2[chIndex]/clockRate); | |
lastValues[chIndex] := AnalogToDigital(chIndex, curamplitudes[chIndex]); | |
if not b2Channels then | |
for i := 0 to cSamplesInSegment - 1 do | |
pStimBuffer^[i + cSamplesInBuffer[chIndex]] := lastValues[chIndex] | |
else | |
for i := 0 to cSamplesInSegment - 1 do | |
TpFramePair(pStimBuffer)^[i + cSamplesInBuffer[chIndex]][chIndex] | |
:= lastValues[chIndex]; | |
cSamplesInBuffer[chIndex] := cSamplesInBuffer[chIndex] + cSamplesInSegment; | |
{third level} | |
cSamplesInSegment := Round(durations3[chIndex]/clockRate); | |
lastValues[chIndex] := AnalogToDigital(chIndex, amplitude3[chIndex]); | |
if not b2Channels then | |
for i := 0 to cSamplesInSegment - 1 do | |
pStimBuffer^[i + cSamplesInBuffer[chIndex]] := lastValues[chIndex] | |
else | |
for i := 0 to cSamplesInSegment - 1 do | |
TpFramePair(pStimBuffer)^[i + cSamplesInBuffer[chIndex]][chIndex] | |
:= lastValues[chIndex]; | |
cSamplesInBuffer[chIndex] := cSamplesInBuffer[chIndex] + cSamplesInSegment; | |
end; | |
end; | |
{Fill rest of buffer} | |
if b2Channels then | |
begin | |
if cSamples > cSamplesInBuffer[chIndex] then | |
for i := 0 to cSamples - cSamplesInBuffer[chIndex] - 1 do | |
TpFramePair(pStimBuffer)^[i + cSamplesInBuffer[chIndex]][chIndex] := lastValues[chIndex]; | |
end | |
else | |
if cSamples > cSamplesInBuffer[chIndex] then | |
for i := 0 to cSamples - cSamplesInBuffer[chIndex] - 1 do | |
pStimBuffer^[i + cSamplesInBuffer[chIndex]] := lastValues[chIndex]; | |
end; | |
end; | |
end; | |
procedure TAnalogOutputBoard.SetAnalogChConvFactors(chIndex: integer; value: double); | |
begin | |
fAnalogChConvFactors[chIndex] := value; | |
end; | |
procedure TAnalogOutputBoard.SetAnalogChNames(chIndex: integer; value: string); | |
begin | |
fAnalogChNames[chIndex] := value; | |
end; | |
procedure TAnalogOutputBoard.SetAnalogChPrefixes(chIndex: integer; value: TPrefix); | |
begin | |
fAnalogChPrefixes[chIndex] := value; | |
end; | |
procedure TAnalogOutputBoard.SetAnalogChUnits(chIndex: integer; value: string); | |
begin | |
fAnalogChUnits[chIndex] := value; | |
end; | |
procedure TAnalogOutputBoard.SetAnalogChZeroOffset(chIndex: integer; value: double); | |
begin | |
fAnalogChZeroOffsets[chIndex] := value; | |
end; | |
procedure TAnalogOutputBoard.SetAnalogOutputEnabled(newAnalogOut: boolean); | |
begin | |
if newAnalogOut = fAnalogOutputEnabled then Exit; | |
{ if fAnalogOutputEnabled then | |
WFM_Group_Control(BoardIndex, 0, AO_START) | |
else | |
begin | |
StopAnalogStimulation; | |
end;} | |
if not newAnalogOut then StopAnalogStimulation; | |
fAnalogOutputEnabled := newAnalogOut; | |
end; | |
procedure TAnalogOutputBoard.SetBoardIndex(newIndex: integer); | |
begin | |
analogOutBoardIndex := newIndex; | |
end; | |
procedure TAnalogOutputBoard.SetInstalled(value: boolean); | |
begin | |
bAnalogOutBoardInstalled := value; | |
end; | |
procedure TAnalogOutputBoard.AnalogOut(chIndex: integer; value: double); | |
begin | |
if fAnalogOutputEnabled then Exit; | |
AO_Write(BoardIndex, chIndex - 1, AnalogToDigital(chIndex, value)); | |
end; | |
function TAnalogOutputBoard.ValidateStimParams(const newParams: TAnalogStimRec): boolean; | |
var cSamples, i: integer; | |
begin | |
Result := True; | |
cSamples := GetTotalSampleCount(newParams); | |
if (cSamples > FIFOSampleCount) then | |
begin | |
MessageDlg('Too many samples in stimulation.', mtError, [mbOK], 0); | |
Result := False; | |
end | |
else if (cSamples < 3) and (cSamples >= 0) then | |
begin | |
MessageDlg('Not enough samples in stimulation.', mtError, [mbOK], 0); | |
Result := False; | |
end | |
else if cSamples < 0 then | |
begin | |
MessageDlg('Invalid Stimulation Parameter.', mtError, [mbOK], 0); | |
Result := False; | |
end; | |
if Result then | |
begin | |
with newParams do | |
for i := 1 to 2 do | |
begin | |
AnalogChConvFactors[i] := chConvFactors[i]; | |
AnalogChNames[i] := chNames[i]; | |
AnalogChPrefixes[i] := chPrefixes[i]; | |
AnalogChUnits[i] := chUnits[i]; | |
AnalogChZeroOffsets[i] := chOffsets[i]; | |
end; | |
analogStimParams := newParams; | |
end; | |
end; | |
function TAnalogOutputBoard.LoadAnalogStimParams(const newParams: TAnalogStimRec): boolean; | |
var interval, iterations: integer; | |
numChans: int16; | |
channelVect: array[0..1] of int16; | |
begin | |
Result := ValidateStimParams(newParams); | |
if Result then | |
if AnalogOutputEnabled and (deviceStatus = dsDetected) then | |
with analogStimParams do | |
begin | |
curamplitudes[1] := amplitude2[1]; | |
curamplitudes[2] := amplitude2[2]; | |
AllocateStimBuffer; | |
ReloadStimParams; | |
case updateRateIndex of | |
0: interval := 1; | |
1: interval := 10; | |
2: interval := 100; | |
3: interval := 1000; | |
else interval := 100; | |
end; | |
{Make sure that the analog output clock is internal} | |
Select_Signal(analogOutputBoard.BoardIndex, ND_OUT_UPDATE_CLOCK_TIMEBASE, | |
ND_INTERNAL_100_KHZ, ND_LOW_TO_HIGH); | |
WFM_ClockRate(BoardIndex, MPUnit.GROUP_1, UPDATE_CLOCK, TIMEBASE_100KHZ, interval, MODE_0); | |
{Load stimulation} | |
channelVect[0] := 0; | |
channelVect[1] := 1; | |
if bNolimit then iterations := 0 else iterations := repeatCount; | |
if bChsEnabled[1] and bChsEnabled[2] then numChans := 2 else numChans := 1; | |
WFM_Load(BoardIndex, numChans, @channelVect, pi16(pStimBuffer), cStimBufferSize, iterations, ENABLE_FIFO_MODE); | |
end; | |
end; | |
procedure TAnalogOutputBoard.Connect; | |
var dummy: array[0..1] of int16; | |
begin | |
if not Installed then | |
fDeviceState := dsNotInstalled | |
else if Init_DA_Brds(BoardIndex, @deviceCode) <> 0 then | |
fDeviceState := dsNotFound | |
else if (deviceCode = PCI_6711) or (deviceCode = PXI_6733) then | |
begin | |
if (deviceCode = PXI_6733) then name := 'sPXI_6733'; | |
fDeviceState := dsDetected; | |
{------------------------ Configure Digital out ------------------------} | |
DIG_Prt_Config(BoardIndex, PORT_0, NO_HANDSHAKING, DIGITAL_OUTPUT); | |
{------------------------ Configure Analog out -------------------------} | |
AO_Configure(BoardIndex, AO0, BIPOLAR_OUT, INTERNAL_REF, REF_VOLTAGE, UPDATE_WHEN_WRITTEN); | |
AO_Configure(BoardIndex, AO1, BIPOLAR_OUT, INTERNAL_REF, REF_VOLTAGE, UPDATE_WHEN_WRITTEN); | |
AO_Configure(BoardIndex, AO2, BIPOLAR_OUT, INTERNAL_REF, REF_VOLTAGE, UPDATE_WHEN_WRITTEN); | |
AO_Configure(BoardIndex, AO3, BIPOLAR_OUT, INTERNAL_REF, REF_VOLTAGE, UPDATE_WHEN_WRITTEN); | |
WFM_DB_Config(BoardIndex, 2, @dummy, DISABLE_DOUBLE_BUFFERING, 0, 0); | |
{------------------------ Configure RTSI -------------------------} | |
{Clock is RTSI_0} | |
Select_Signal(BoardIndex, ND_OUT_UPDATE_CLOCK_TIMEBASE, ND_RTSI_0, ND_LOW_TO_HIGH); | |
{Start of data out is RTSI_1} | |
Select_Signal(BoardIndex, ND_OUT_START_TRIGGER, ND_RTSI_1, ND_LOW_TO_HIGH); | |
{Photon counting handshaking signals on RTSI 2 and RTSI 3} | |
Select_Signal(BoardIndex, ND_OUT_START_TRIGGER, ND_RTSI_2, ND_LOW_TO_HIGH); | |
Select_Signal(BoardIndex, ND_OUT_START_TRIGGER, ND_RTSI_3, ND_LOW_TO_HIGH); | |
end | |
else | |
fDeviceState := dsNotInstalled; | |
end; | |
function TAnalogOutputBoard.DigitalToAnalog(chIndex: integer; value: int16): double; | |
begin | |
Result := PrefixToFactor(AnalogChPrefixes[chIndex]) * | |
(AnalogChConvFactors[chIndex] * OutputRange * value / 2048 | |
+ AnalogChZeroOffsets[chIndex]); | |
end; | |
function TAnalogOutputBoard.OpenAnalogStimulation(const stimFilename: string): boolean; | |
var iniFile: TIniFile; i: integer; | |
begin | |
iniFile := TIniFile.Create(stimFilename); | |
try | |
Result := LoadAnalogStimFile(analogStimParams, iniFile); | |
if Result then | |
begin | |
for i := 1 to 2 do | |
begin | |
fAnalogChConvFactors[i] := analogStimParams.chConvFactors[i]; | |
fAnalogChNames[i] := analogStimParams.chNames[i]; | |
fAnalogChPrefixes[i] := analogStimParams.chPrefixes[i]; | |
fAnalogChUnits[i] := analogStimParams.chUnits[i]; | |
fAnalogChZeroOffsets[i] := analogStimParams.chOffsets[i]; | |
end; | |
analogStimParams.filename := stimFilename; | |
end; | |
finally | |
iniFile.Free; | |
end; | |
end; | |
procedure TAnalogOutputBoard.SaveAnalogStimulation(const stimFilename: string); | |
var iniFile: TIniFile; | |
begin | |
iniFile := TIniFile.Create(stimFilename); | |
try | |
SaveAnalogStimFile(analogStimParams, iniFile); | |
finally | |
iniFile.Free; | |
end; | |
end; | |
procedure TAnalogOutputBoard.StartAnalogStimulation; | |
begin | |
if AnalogOutputEnabled and (deviceStatus = dsDetected) then | |
WFM_Group_Control(BoardIndex, 1, AO_START) | |
end; | |
function TAnalogOutputBoard.StopAnalogStimulation: boolean; | |
begin | |
Result := True; | |
if AnalogOutputEnabled and (deviceStatus = dsDetected) then | |
begin | |
WFM_Group_Control(BoardIndex, 1, AO_CLEAR); | |
{prepare for next round} | |
with analogStimParams do | |
begin | |
{incremental mode is prerequisite} | |
if bChsEnabled[1] and (stimTypes[1] = Ord(stIncrement)) then | |
begin | |
curamplitudes[1] := curamplitudes[1] + ampincrements[1]; | |
if ampincrements[1] >= 0 then | |
begin | |
if curamplitudes[1] > toamplitudes[1] then | |
curamplitudes[1] := toamplitudes[1] | |
else | |
Result := False; | |
end | |
else | |
begin | |
if curamplitudes[1] < toamplitudes[1] then | |
curamplitudes[1] := toamplitudes[1] | |
else | |
Result := False; | |
end; | |
end; | |
if bChsEnabled[2] and (stimTypes[2] = Ord(stIncrement)) then | |
begin | |
curamplitudes[2] := curamplitudes[2] + ampincrements[2]; | |
if ampincrements[2] >= 0 then | |
begin | |
if curamplitudes[2] > toamplitudes[2] then | |
curamplitudes[2] := toamplitudes[2] | |
else | |
Result := False; | |
end | |
else | |
begin | |
if curamplitudes[2] < toamplitudes[2] then | |
curamplitudes[2] := toamplitudes[2] | |
else | |
Result := False; | |
end; | |
end; | |
if ((stimTypes[1] = Ord(stIncrement)) or (stimTypes[2] = Ord(stIncrement))) and not Result then | |
LoadAnalogStimParams(analogStimParams); | |
end; | |
end; | |
{Returns False only if stimTypes were 2 (incremental), curamplitudes are valid | |
and scan trigger is Analog stimulation} | |
{Result := Result or not (Mainform.Configuration.ScanTrigger = stAnalogStimulation);} | |
{ fAnalogOutputEnabled := Result;} | |
{Mainform.Button5.Down := Result;} | |
end; | |
constructor TAnalogOutputBoard.Create; | |
begin | |
fOutputRange := 10; | |
FIFOSampleCount := 8192; | |
name := 'PCI-6711'; | |
with analogStimParams do | |
begin | |
updateRateIndex := 2; {1 ms} | |
repeatCount := 1; | |
bNolimit := False; | |
bChsEnabled[1]:= True; bChsEnabled[2]:= True; | |
chNames[1]:= AnalogChNames[1]; chNames[2]:= AnalogChNames[2]; | |
chUnits[1]:= AnalogChUnits[1]; chUnits[2]:= AnalogChUnits[2]; | |
chPrefixes[1]:= AnalogChPrefixes[1]; chPrefixes[2]:= AnalogChPrefixes[2]; | |
chConvFactors[1]:= AnalogChConvFactors[1]; chConvFactors[2]:= AnalogChConvFactors[2]; | |
chOffsets[1]:= AnalogChZeroOffsets[1]; chOffsets[2]:= AnalogChZeroOffsets[2]; | |
holdingValues[1]:= 0; holdingValues[2]:= 0; | |
trainRepeats[1]:= 1; trainRepeats[2]:= 1; | |
stimTypes[1]:= 1; stimTypes[2]:= 1; {0: seal, 1: train, 2: incremental} | |
durations1[1]:= 10; durations1[2]:= 10; | |
durations2[1]:= 10; durations2[2]:= 10; | |
durations3[1]:= 10; durations3[2]:= 10; | |
amplitude1[1]:= 0; amplitude1[2]:= 0; | |
amplitude2[1]:= 1; amplitude2[2]:= 1; | |
amplitude3[1]:= 0; amplitude3[2]:= 0; | |
toamplitudes[1]:= 5; toamplitudes[2]:= 5; | |
ampincrements[1]:= 4; ampincrements[2]:= 4; | |
end; | |
Connect; | |
LoadAnalogStimParams(analogStimParams); {forces creation of buffers} | |
end; | |
destructor TAnalogOutputBoard.Destroy; | |
begin | |
DestroyStimBuffer; | |
inherited Destroy; | |
end; | |
{**************************** Optics Output Board *****************************} | |
function TOpticsOutputBoard.GetBoardIndex: integer; | |
begin | |
Result := opticsOutBoardIndex; | |
end; | |
function TOpticsOutputBoard.GetInstalled: boolean; | |
begin | |
Result := bOpticsOutputBoardInstalled; | |
end; | |
procedure TOpticsOutputBoard.SetBoardIndex(newIndex: integer); | |
begin | |
opticsOutBoardIndex := newIndex; | |
end; | |
procedure TOpticsOutputBoard.SetInstalled(value: boolean); | |
begin | |
bOpticsOutputBoardInstalled := value; | |
end; | |
{**************************** Photon Counting Board ***************************} | |
function TPhotonCountingBoard.GetBoardIndex: integer; | |
begin | |
Result := PhotonCountingBoardIndex; | |
end; | |
function TPhotonCountingBoard.GetInstalled: boolean; | |
begin | |
Result := bPhotonCountingBoardInstalled; | |
end; | |
procedure TPhotonCountingBoard.SetBoardIndex(newIndex: integer); | |
begin | |
PhotonCountingBoardIndex := newIndex; | |
end; | |
procedure TPhotonCountingBoard.SetInstalled(value: boolean); | |
begin | |
bPhotonCountingBoardInstalled := value; | |
end; | |
procedure TPhotonCountingBoard.Connect; | |
begin | |
if not Installed then | |
fDeviceState := dsNotInstalled | |
else | |
begin | |
if Init_DA_Brds(BoardIndex, @deviceCode) <> 0 then | |
fDeviceState := dsNotFound | |
else if (deviceCode = PCI_DIO_32HS) or (deviceCode = PCI_6534) then | |
begin | |
if deviceCode = PCI_6534 then name := 'PCI-6534'; | |
{Gets REQ1 from RTSI_2} | |
if RTSI_Conn(BoardIndex, REQ1, RTSI_2, REQ_RECEIVE) <> 0 then | |
fDeviceState := dsNotInstalled | |
else | |
fDeviceState := dsDetected; | |
// {Gets REQ2 from RTSI_2} | |
// if RTSI_Conn(BoardIndex, REQ1, RTSI_2, REQ_RECEIVE) <> 0 then | |
// fDeviceState := dsNotInstalled | |
// else | |
// fDeviceState := dsDetected; | |
end | |
else | |
fDeviceState := dsNotInstalled; | |
end; | |
end; | |
constructor TPhotonCountingBoard.Create; | |
begin | |
name := sPCI_DIO_32HS; | |
Connect; | |
end; | |
destructor TPhotonCountingBoard.Destroy; | |
begin | |
if deviceStatus = dsDetected then | |
RTSI_Clear(boardIndex); | |
inherited Destroy; | |
end; | |
{******************************** Laser Shutter *******************************} | |
function TLaserShutter.GetAnalogBoardControlsShutter: boolean; | |
begin | |
Result := bAnalogOutBrdControlsShutter; | |
end; | |
function TLaserShutter.GetCloseAfterSection: boolean; | |
begin | |
Result := bCloseShutterAfterSection; | |
end; | |
function TLaserShutter.GetMultifunctionDIOIndex: integer; | |
begin | |
Result := multifuncBoardShutterIndex; | |
end; | |
function TLaserShutter.GetOpenDelay: integer; | |
begin | |
Result := shutterDelay; | |
end; | |
procedure TLaserShutter.SetAnalogBoardControlsShutter(value: boolean); | |
begin | |
bAnalogOutBrdControlsShutter := Value; | |
end; | |
procedure TLaserShutter.SetCloseAfterSection(value: boolean); | |
begin | |
bCloseShutterAfterSection := Value; | |
end; | |
procedure TLaserShutter.SetMultifunctionDIOIndex(newIndex: integer); | |
begin | |
multifuncBoardShutterIndex := newIndex; | |
end; | |
procedure TLaserShutter.SetOpenDelay(newDelay: integer); | |
begin | |
shutterDelay := newDelay; | |
end; | |
procedure TLaserShutter.SetClosed(bClosed: boolean); | |
var bState: int16; | |
mask: integer; {added 02-27-08} | |
begin | |
if fDeviceState = dsNotInstalled then | |
fbClosed := False {there is no shutter} | |
else | |
if bClosed <> fbClosed then | |
begin | |
if bClosed then bState := TTL_LOW else bState := TTL_HIGH; | |
if bAnalogOutBrdControlsShutter then | |
DIG_Out_Line(analogOutputBoard.BoardIndex, PORT_0, SHUTTER_LINE, bState) | |
else | |
begin | |
{begin modification 02-27-08} | |
{sets value of shutter value into digital port} | |
mask := 1 shl multifuncBoardShutterIndex; | |
if bState = TTL_HIGH then | |
multifunctionBoard.fDigitalPort := multifunctionBoard.fDigitalPort or mask | |
else | |
multifunctionBoard.fDigitalPort := multifunctionBoard.fDigitalPort and (not mask); | |
{end modification 02-27-08} | |
DIG_Out_Line(multifunctionBoard.BoardIndex, PORT_0, multifuncBoardShutterIndex, bState); | |
end; | |
Wait(openDelay); | |
fbClosed := bClosed; | |
end; | |
end; | |
procedure TLaserShutter.Wait(nms: integer); | |
var oldTime, newTime: integer; | |
begin | |
if nms <= 0 then Exit; | |
{Wait for ~ openDelay ms for the shutter to open or close completely} | |
oldTime := timeGetTime; {multimedia timer} | |
repeat | |
newTime := timeGetTime; | |
if newTime < oldTime then oldTime := timeGetTime; {wrap around every 49.1 days...} | |
until newTime > oldTime + nms; | |
end; | |
procedure TLaserShutter.OpenShutter; | |
begin | |
Closed := False; | |
end; | |
procedure TLaserShutter.Connect; | |
begin | |
if AnalogBoardControlsShutter then | |
begin | |
if analogOutputBoard.deviceStatus = dsDetected then | |
fDeviceState := dsDetected | |
else | |
fDeviceState := dsNotInstalled; | |
end | |
else | |
fDeviceState := dsDetected; | |
end; | |
constructor TLaserShutter.Create; | |
begin | |
autoObject := TMPLaserShutter.Create; | |
name := 'Laser Shutter'; | |
Connect; | |
end; | |
destructor TLaserShutter.Destroy; | |
begin | |
autoObject := nil; | |
inherited Destroy; | |
end; | |
{ | |
procedure TOriginalShutter.SetDeviceState(newState: TDeviceState); | |
begin | |
end; | |
} | |
{********************************** Z-Stepper *********************************} | |
function TZStepper.GetCOMPort: integer; | |
begin | |
Result := zStepperCOMPort; | |
end; | |
function TZStepper.GetCOMSpeed: integer; | |
begin | |
Result := zStepperCOMSpeed; | |
end; | |
function TZStepper.GetInvertZ: boolean; | |
begin | |
Result := zStepperInvert; | |
end; | |
procedure TZStepper.OnMoveStarted; | |
begin | |
Screen.Cursor := crHourGlass; | |
Mainform.Shape4.Brush.Color := clRed; | |
Mainform.Shape4.Refresh; | |
end; | |
procedure TZStepper.OnMoveFinished; | |
begin | |
Mainform.Shape4.Brush.Color :=clLime; | |
Mainform.Shape4.Refresh; | |
Mainform.UpdateZCaptions; | |
Screen.Cursor := crDefault; | |
end; | |
procedure TZStepper.SetCOMPort(value: integer); | |
begin | |
zStepperCOMPort := value; | |
end; | |
procedure TZStepper.SetCOMSpeed(value: integer); | |
begin | |
zStepperCOMSpeed := value; | |
end; | |
procedure TZStepper.SetInvertZ(value: boolean); | |
begin | |
zStepperInvert := value; | |
end; | |
procedure TZStepper.SetSpeed(newspeed: integer); | |
begin | |
if (newspeed < 1) or (newspeed > 20) then Exit; | |
zStepperSpeed := newSpeed; | |
end; | |
procedure TZStepper.SetZPosition(newPos: double); | |
begin | |
SetZ(newPos); | |
end; | |
function TZStepper.GetSpeed: integer; | |
begin | |
Result := zStepperSpeed; | |
end; | |
procedure TZStepper.GetZ(var newZ: double); | |
begin | |
newZ := newZ; | |
end; | |
procedure TZStepper.MoveToRelativeZ(newDeltaZ: double); | |
begin | |
if not fBusy then | |
begin | |
OnMoveStarted; | |
if InvertZ then newDeltaZ := -newDeltaZ; | |
fZPosition := fzPosition + newDeltaZ; | |
end; | |
end; | |
procedure TZStepper.SetZ(var newZ: double); | |
begin | |
if fBusy then Exit; | |
OnMoveStarted; | |
// fZPosition := newZ; | |
end; | |
function TZStepper.TravelTime(zTravel: integer; speedIndex: integer): double; | |
begin | |
Result := 0; | |
end; | |
procedure TZStepper.StartFastScan; | |
begin | |
bFastScanInProgress := True; | |
end; | |
procedure TZStepper.StopFastScan; | |
begin | |
bFastScanInProgress := False; | |
end; | |
procedure TZStepper.StopMove; | |
begin | |
if bTimerActive then timeKillEvent(zTimer); | |
bTimerActive := False; | |
end; | |
{synchronous call} | |
procedure TZStepper.MoveToZ(newZ: double); | |
begin | |
OnMoveStarted; | |
end; | |
{synchronous call} | |
function TZStepper.ReadZ: double; | |
begin | |
Result := fZPosition; | |
end; | |
{synchronous call} | |
procedure TZStepper.ShiftByZ(deltaZ: double); | |
begin | |
OnMoveStarted; | |
if InvertZ then deltaZ := - deltaZ; | |
fzPosition := fzPosition + deltaZ; | |
end; | |
constructor TZStepper.Create; | |
var timeCaps: TTimeCaps; | |
begin | |
inherited Create; | |
{ fSpeed := 5;} {5 ms per pulse} | |
name := 'Z- stepper'; | |
autoObject := TMPZStepper.Create; | |
if timeGetDevCaps(@timeCaps, SizeOf(TTimeCaps)) = MMSYSERR_NOERROR then | |
begin | |
minTimerResolution := Min(Max(timeCaps.wPeriodMin, TARGET_RESOLUTION), timeCaps.wPeriodMax); | |
maxTimerResolution := timeCaps.wPeriodMax; | |
timeBeginPeriod(minTimerResolution); | |
end; | |
end; | |
destructor TZStepper.Destroy; | |
begin | |
autoObject := nil; | |
timeEndPeriod(minTimerResolution); | |
inherited Destroy; | |
end; | |
{******************************** Earl's Stepper ******************************} | |
{procedure TEarlStepper.SetDeviceState(newState: TDeviceState); | |
begin | |
fDeviceState := dsDetected; | |
end;} | |
procedure TEarlStepper.Connect; | |
begin | |
fDeviceState := dsDetected; | |
end; | |
procedure TEarlStepper.SetSpeed(newspeed: integer); | |
begin | |
if fBusy then Exit; | |
inherited SetSpeed(newspeed); | |
end; | |
procedure TEarlStepper.GetZ(var newZ: double); | |
begin | |
newZ := ZPosition; | |
Mainform.UpdateZCaptions; | |
end; | |
const | |
UP_SEQUENCE = $FE; {first bit low} | |
DOWN_SEQUENCE = $FD; | |
RESET_SEQUENCE = $FF; | |
procedure MovingZCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; | |
begin | |
with TEarlStepper(dwUser) do | |
begin | |
if Odd(curZsequenceCount) then | |
DIG_Out_Prt(multifunctionBoard.boardIndex, PORT_0, zPattern or multifunctionBoard.DigitalPort) | |
else | |
DIG_Out_Prt(multifunctionBoard.boardIndex, PORT_0, RESET_SEQUENCE or multifunctionBoard.DigitalPort); | |
curZsequenceCount := curZsequenceCount + 1; | |
if curZsequenceCount >= zsequenceCount then | |
begin | |
if bTimerActive then timeKillEvent(zTimer); | |
bTimerActive := False; | |
OnMoveFinished; | |
fBusy := False; | |
end; | |
end; | |
end; | |
procedure TEarlStepper.MoveToRelativeZ(newDeltaZ: double); | |
begin | |
if not fBusy then | |
begin | |
inherited MoveToRelativeZ(newDeltaZ); | |
if InvertZ then newDeltaZ := - newDeltaZ; | |
fBusy := True; | |
{creates a digital pattern: converts microns into steps} | |
zSequenceCount := 2 * Round(Abs(newDeltaZ) / stepSize); | |
curZsequenceCount := 0; | |
if newDeltaZ < 0 then zPattern := DOWN_SEQUENCE else zPattern := UP_SEQUENCE; | |
bTimerActive := True; | |
zTimer := timeSetEvent(21 - Speed {2 ms / step}, 0, MovingZCallback, DWORD(self), TIME_PERIODIC); | |
end; | |
end; | |
procedure EarlFastStackCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; | |
var newPower: double; | |
currentDisplacement: double; | |
begin | |
with TEarlStepper(dwUser) do | |
begin | |
if Odd(curZsequenceCount) then | |
begin | |
DIG_Out_Prt(multifunctionBoard.boardIndex, PORT_0, zPattern or multifunctionBoard.DigitalPort); | |
if zPattern = UP_SEQUENCE then | |
fZPosition := fZPosition + stepSize | |
else | |
fZPosition := fZPosition - stepSize; | |
end | |
else | |
DIG_Out_Prt(multifunctionBoard.boardIndex, PORT_0, RESET_SEQUENCE or multifunctionBoard.DigitalPort); | |
curZsequenceCount := curZsequenceCount + 1; | |
{Adjust laser power here} | |
with Mainform.Configuration, Mainform.engine do | |
if IntensityControl <> IC_NO_CONTROL then | |
begin | |
currentDisplacement := - startFastScanPosition + fZPosition; | |
if IntensityControl = IC_LINEAR then | |
newPower := currentDisplacement * (FinalIntensity - InitialIntensity)/AtZDistance | |
+ InitialIntensity | |
else | |
begin | |
if InitialIntensity <= 0 then InitialIntensity := 1; | |
newPower := InitialIntensity * | |
exp(currentDisplacement * Ln(FinalIntensity/InitialIntensity) / AtZDistance); | |
end; | |
if Abs(newPower- LaserControl.Power) > 0 then | |
begin | |
analogOutputBoard.AnalogOut(1, newPower/10); | |
LaserControl.Power := newPower; | |
end; | |
end; | |
if curZsequenceCount >= zsequenceCount then | |
begin | |
curFastRepeatCount := curFastRepeatCount + 1; | |
if curFastRepeatCount >= Mainform.Configuration.FastStackRepeatCount then | |
begin | |
if bTimerActive then timeKillEvent(zTimer); | |
bTimerActive := False; | |
bFastScanInProgress := False; | |
PostMessage(Mainform.Handle, WM_FASTSTACK_ENDED, 0, 0); | |
end | |
else | |
begin | |
{we invert the pattern here and go backwards} | |
if zPattern = DOWN_SEQUENCE then zPattern := UP_SEQUENCE else | |
zPattern := DOWN_SEQUENCE; | |
curZsequenceCount := 0; | |
end; | |
end; | |
end; | |
end; | |
procedure TEarlStepper.StartFastScan; | |
begin | |
inherited StartFastScan; | |
startFastScanPosition := ZPosition; | |
with Mainform.configuration do | |
begin | |
zSequenceCount := 2 * Round(Abs(zDistance) / stepSize); | |
curZsequenceCount := 0; | |
curFastRepeatCount := 0; | |
if zDistance < 0 then zPattern := DOWN_SEQUENCE else zPattern := UP_SEQUENCE; | |
{The timer is set to fire every 61 - TravelSpeed millisecond} | |
bTimerActive := True; | |
zTimer := timeSetEvent(61 - TravelSpeed, 0, EarlFastStackCallback, DWORD(self), TIME_PERIODIC); | |
end; | |
end; | |
procedure TEarlStepper.StopFastScan; | |
begin | |
if not bFastScanInProgress then Exit; | |
if bTimerActive then timeKillEvent(zTimer); | |
bTimerActive := False; | |
inherited StopFastScan; | |
end; | |
procedure TEarlStepper.SetZ(var newZ: double); | |
var newDeltaZ: double; | |
begin | |
newDeltaZ := newZ - ZPosition; | |
inherited SetZ(newZ); | |
MoveToRelativeZ(newDeltaZ); | |
repeat | |
Application.ProcessMessages; | |
until not Busy; | |
end; | |
function TEarlStepper.TravelTime(zTravel: integer; speedIndex: integer): double; | |
begin | |
{speedIndex = 1: slowest, speed index = 60: fastest} | |
{8: conversion to 1/8 microns | |
2: Low and High | |
61 - speedIndex: duration in ms of a pulse} | |
Result := Abs(zTravel) * 8 * 2 * (61 - speedIndex) / 1000; | |
end; | |
procedure TEarlStepper.MoveToZ(newZ: double); | |
begin | |
SetZ(newZ); | |
end; | |
function TEarlStepper.ReadZ: double; | |
begin | |
Result := ZPosition; | |
end; | |
procedure TEarlStepper.ShiftByZ(deltaZ: double); | |
begin | |
MoveToRelativeZ(deltaZ); | |
repeat | |
Application.ProcessMessages; | |
until not Busy; | |
end; | |
constructor TEarlStepper.Create; | |
begin | |
inherited Create; | |
fDeviceState := dsDetected; | |
name := 'Earl''s stepper'; | |
{ fSpeed := 5; }{5 ms per pulse} | |
fStepSize := 0.125; | |
end; | |
destructor TEarlStepper.Destroy; | |
begin | |
inherited Destroy; | |
end; | |
{********************************** TZMP285 *********************************} | |
function TZMP285.GetDeviceState: TDeviceState; | |
begin | |
Result := xyzMP285.GetDeviceState; | |
end; | |
procedure TZMP285.Connect; | |
begin | |
xyzMP285.Connect; | |
end; | |
procedure TZMP285.SetSpeed(speedIndex: integer); | |
begin | |
xyzMP285.SetSpeed(speedIndex); | |
end; | |
procedure TZMP285.GetZ(var newZ: double); | |
begin | |
xyzMP285.GetXYZ; {returns values in zStepper and XYTable} | |
newZ := fzPosition; | |
end; | |
procedure TZMP285.MoveToRelativeZ(newDeltaZ: double); | |
begin | |
if not fBusy then | |
begin | |
{updates current position} | |
xyzMP285.GetXYZ; | |
inherited MoveToRelativeZ(newDeltaZ); {updates fZPosition} | |
fBusy := True; | |
{returns values in zStepper and XYTable} | |
xyzMP285.SetXYZ(xyTable.fXPosition, xyTable.fYPosition, fZPosition); | |
end; | |
end; | |
{Asynchronous call} | |
procedure TZMP285.SetZ(var newZ: double); | |
begin | |
if not fBusy then | |
begin | |
{updates current position} | |
xyzMP285.GetXYZ; | |
inherited SetZ(newZ); | |
xyzMP285.SetXYZ(xyTable.fXPosition, xyTable.fYPosition, fZPosition); | |
newZ := fZPosition; | |
end; | |
end; | |
{Synchronous call} | |
procedure TZMP285.MoveToZ(newZ: double); | |
begin | |
if not fBusy then | |
begin | |
{updates current position} | |
xyzMP285.GetXYZ; | |
inherited MoveToZ(newZ); | |
fBusy := True; | |
xyzMP285.SetXYZ(xyTable.fXPosition, xyTable.fYPosition, fZPosition); | |
repeat | |
Application.ProcessMessages; | |
{xyzTriggerData sets fBusy flags to False} | |
until not Busy; | |
end; | |
end; | |
function TZMP285.ReadZ: double; | |
begin | |
if not fBusy then | |
begin | |
xyzMP285.GetXYZ; | |
Result := fZPosition; | |
end | |
else | |
Result := 0; | |
end; | |
{synchronous calls; returns when complete} | |
procedure TZMP285.ShiftByZ(deltaZ: double); | |
begin | |
if not fBusy then | |
begin | |
xyzMP285.GetXYZ; | |
inherited ShiftByZ(deltaZ); | |
fBusy := True; | |
xyzMP285.SetXYZ(XYTable.fXPosition, XYTable.fYPosition, ZStepper.fzPosition); | |
repeat | |
Application.ProcessMessages; | |
until not Busy; | |
end; | |
end; | |
function TZMP285.TravelTime(zTravel: integer; speedIndex: integer): double; | |
begin | |
{2.9 mm / s: max speed of MP-285} | |
{speedIndex = 1: slowest, speed index = 60: fastest: 1 step / 20 ms : 10 um/s} | |
{1 um = 5 steps; minimal callback time: 20 ms (because of serial port)} | |
{80 - speedIndex: callback time (in ms)} | |
Result := 5 {microns/step} * Abs(zTravel) * (80 - speedIndex) / 1000; | |
end; | |
procedure ZMP285FastStackCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; | |
var newPower: integer; | |
currentDisplacement: double; | |
begin | |
with TZMP285(dwUser) do | |
begin | |
if not Odd(curFastRepeatCount) and (Mainform.Configuration.zDistance < 0) then | |
fZPosition := fZPosition - stepSize | |
else | |
fZPosition := fZPosition + stepSize; | |
xyzMP285.SetXYZFast(XYTable.XPosition, XYTable.YPosition, ZPosition); | |
{Adjust laser power here} | |
with Mainform.Configuration, Mainform.engine do | |
if IntensityControl <> IC_NO_CONTROL then | |
begin | |
currentDisplacement := - startFastScanPosition + fZPosition; | |
if IntensityControl = IC_LINEAR then | |
newPower := Round(currentDisplacement * (FinalIntensity - InitialIntensity)/AtZDistance | |
+ InitialIntensity) | |
else | |
begin | |
if InitialIntensity <= 0 then InitialIntensity := 1; | |
newPower := Round(InitialIntensity * | |
exp(currentDisplacement * Ln(FinalIntensity/InitialIntensity) / AtZDistance)); | |
end; | |
if Abs(newPower- LaserControl.Power) > 0 then LaserControl.Power := newPower; | |
end; | |
if (ZPosition = startFastScanPosition + Mainform.Configuration.zDistance) or | |
(ZPosition = startFastScanPosition) then | |
begin | |
curFastRepeatCount := curFastRepeatCount + 1; | |
if curFastRepeatCount >= Mainform.Configuration.FastStackRepeatCount then | |
begin | |
if bTimerActive then timeKillEvent(zTimer); | |
bTimerActive := False; | |
bFastScanInProgress := False; | |
PostMessage(Mainform.Handle, WM_FASTSTACK_ENDED, 0, 0); | |
end; | |
end; | |
end; | |
end; | |
procedure TZMP285.StartFastScan; | |
begin | |
inherited StartFastScan; | |
GetZ(startFastScanPosition); {we get the initial position} | |
with Mainform.configuration do | |
begin | |
curFastRepeatCount := 0; | |
{The timer is set to fire every 80 - TravelSpeed millisecond} | |
bTimerActive := True; | |
zTimer := timeSetEvent(80 - TravelSpeed, 0, ZMP285FastStackCallback, DWORD(self), TIME_PERIODIC); | |
end; | |
end; | |
procedure TZMP285.StopFastScan; | |
begin | |
if not bFastScanInProgress then Exit; | |
if bTimerActive then timeKillEvent(zTimer); | |
bTimerActive := False; | |
inherited StopFastScan; | |
{enables MP285 no matter what} | |
end; | |
constructor TZMP285.Create; | |
begin | |
inherited Create; | |
name := 'Sutter MP-285 Z-Stepper'; | |
{ fSpeed := 5;} {medium speed} | |
fStepSize := 0.2; {5 microsteps / microns} | |
end; | |
destructor TZMP285.Destroy; | |
begin | |
FreeAndNil(xyzMP285); | |
inherited Destroy; | |
end; | |
{********************************** X-Y Table *********************************} | |
function TXYTable.GetCOMPort: integer; | |
begin | |
Result := xydeviceCOMPortIndex; | |
end; | |
function TXYTable.GetCOMSpeed: integer; | |
begin | |
Result := xydeviceCOMSpeedIndex; | |
end; | |
function TXYTable.GetInvertX: boolean; | |
begin | |
Result := bxydeviceInvertX; | |
end; | |
function TXYTable.GetInvertY: boolean; | |
begin | |
Result := bxydeviceInvertY; | |
end; | |
function TXYTable.GetSpeed: integer; | |
begin | |
Result := xydeviceManualSpeed; | |
end; | |
procedure TXYTable.OnMoveStarted; | |
begin | |
fBusy := True; | |
Screen.Cursor := crHourGlass; | |
Mainform.Shape3.Brush.Color := clRed; | |
Mainform.Shape3.Refresh; | |
end; | |
procedure TXYTable.OnMoveFinished; | |
begin | |
Mainform.Shape3.Brush.Color := clLime; | |
Mainform.Shape3.Refresh; | |
fBusy := False; | |
Mainform.UpdateXYCaptions; | |
Screen.Cursor := crDefault; | |
end; | |
procedure TXYTable.SetCOMPort(portIndex: integer); | |
begin | |
xydeviceCOMPortIndex := portIndex; | |
end; | |
procedure TXYTable.SetCOMSpeed(portSpeed: integer); | |
begin | |
xydeviceCOMSpeedIndex := portSpeed; | |
end; | |
procedure TXYTable.SetInvertX(bInvert: boolean); | |
begin | |
bxydeviceInvertX := bInvert; | |
end; | |
procedure TXYTable.SetInvertY(bInvert: boolean); | |
begin | |
bxydeviceInvertY := bInvert; | |
end; | |
procedure TXYTable.SetSpeed(value: integer); | |
begin | |
xydeviceManualSpeed := value; | |
end; | |
{async} | |
procedure TXYTable.GetXY(var newX, newY: integer); | |
begin | |
newX := 0; newY := 0; | |
end; | |
{async} | |
procedure TXYTable.SetXY(var newX, newY: integer); | |
begin | |
OnMoveStarted; | |
end; | |
{async} | |
procedure TXYTable.SetRelativeXY(deltaX, deltaY: integer); | |
begin | |
OnMoveStarted; | |
end; | |
procedure TXYTable.XYCommand(const sCommand: string); | |
begin | |
{do nothing - overriden by classes descending from TXYTable} | |
end; | |
procedure TXYTable.GalilWaitForMotionComplete; | |
begin | |
{do nothing - overriden by classes descending from TXYTable} | |
end; | |
{sync} | |
procedure TXYTable.MoveToXY(newX, newY: integer); | |
begin | |
OnMoveStarted; | |
end; | |
{sync} | |
procedure TXYTable.ReadXY(var x, y: integer); | |
begin | |
x := 0; y := 0; | |
end; | |
{sync} | |
procedure TXYTable.ShiftByXY(deltaX, deltaY: integer); | |
begin | |
OnMoveStarted; | |
end; | |
constructor TXYTable.Create; | |
begin | |
inherited Create; | |
name := 'X-Y Table'; | |
autoObject := TMPXYTable.Create; | |
end; | |
destructor TXYTable.Destroy; | |
begin | |
autoObject := nil; | |
inherited Destroy; | |
end; | |
{********************************** NEAT 300 *********************************} | |
const MICRONS_PER_STEP = 508; {0.0508 microns per steps; steps / microns = 10000 / 508} | |
procedure TNEAT300.TriggerData(CP: TObject; TriggerHandle: Word); | |
var deltaX, deltaY: integer; | |
begin | |
if neatStatus = neatOK then Exit; | |
if triggerHandle = CaretTriggerHandle then | |
case neatStatus of | |
neatTERM3: {we cascade all commands} | |
begin | |
{TERM3 string was successfully processed by the NEAT controller | |
we go to the next command and disable the watchdog timer} | |
neatStatus := neatMFE; {Move Finished Enabled} | |
serialPort.SetTimerTrigger(TimerHandle, 32, False); | |
serialPort.PutString('MFE' + CRLF); | |
end; | |
neatMFE: | |
begin | |
neatStatus := neatAA; {all axes} | |
serialPort.PutString('AA' + CRLF); | |
end; | |
neatAA: | |
begin | |
{skip neatSE to prevent encoders from resetting: 12 Dec 05} | |
{ neatStatus := neatSE; all axes | |
serialPort.PutString('SE0,0' + CRLF); | |
end; | |
neatSE: | |
begin } | |
neatStatus := neatJE; {all axes} | |
serialPort.PutString('JE1,1' + CRLF); | |
end; | |
neatJE: | |
begin | |
fDeviceState := dsDetected; | |
neatStatus := neatOK; | |
end; | |
neatREAD: | |
begin | |
ParseReturnedString; | |
if (s1 <> '') and (s2 <> '') then | |
begin | |
try | |
fXPosition := StrToInt(s1); | |
fYPosition := StrToInt(s2); | |
except | |
fXPosition := 0; | |
fYPosition := 0; | |
end; | |
pNewX^ := fXPosition; | |
pNewY^ := fYPosition; | |
neatStatus := neatOK; | |
fBusy := False; | |
end; | |
end; | |
neatREADUPDATE: | |
begin | |
ParseReturnedString; | |
if (s1 <> '') and (s2 <> '') then | |
begin | |
try | |
fXPosition := StrToInt(s1); | |
fYPosition := StrToInt(s2); | |
except | |
fXPosition := 0; | |
fYPosition := 0; | |
end; | |
pNewX^ := fXPosition; | |
pNewY^ := fYPosition; | |
neatStatus := neatOK; | |
OnMoveFinished; | |
{enables joystick back} | |
serialPort.PutString('JE1,1' + CRLF); | |
end; | |
fBusy := False; | |
end; | |
neatREADCLOSELOOP: | |
begin | |
ParseReturnedString; | |
if (s1 <> '') and (s2 <> '') then | |
begin | |
try | |
fXPosition := StrToInt(s1); | |
fYPosition := StrToInt(s2); | |
except | |
fXPosition := 0; | |
fYPosition := 0; | |
end; | |
pNewX^ := fXPosition; | |
pNewY^ := fYPosition; | |
deltaX := Muldiv(10000, desiredX - fXposition, MICRONS_PER_STEP); | |
deltaY := Muldiv(10000, desiredY - fYPosition, MICRONS_PER_STEP); | |
if ((Abs(deltaX) <= 1) and (Abs(deltaY) <= 1)) or | |
(iterationCount = MAX_CLOSE_LOOP_ITERATIONS) then | |
begin | |
neatStatus := neatOK; | |
OnMoveFinished; | |
{enables joystick back} | |
serialPort.PutString('JE1,1' + CRLF); | |
fBusy := False; | |
end | |
else | |
begin | |
neatStatus := neatMOVECLOSELOOP; | |
serialPort.PutString('MR' + IntToStr(deltaX) + ',' + IntToStr(deltaY) + CRLF); | |
end; | |
end; | |
end; | |
neatCOMMAND, neatSETSPEED: | |
begin | |
fBusy := False; | |
neatStatus := neatOK; | |
end; | |
end | |
else if triggerHandle = FTriggerHandle then | |
case neatStatus of | |
neatMOVE: | |
begin | |
neatStatus := neatREADUPDATE; | |
serialPort.PutString('RE' + CRLF); | |
end; | |
neatMOVECLOSELOOP: | |
begin | |
iterationCount := iterationCount + 1; | |
neatstatus := neatREADCLOSELOOP; | |
serialPort.PutString('RE' + CRLF); | |
end; | |
end; | |
sSerial := ''; | |
if neatStatus = neatOK then fBusy := False; | |
end; | |
procedure TNEAT300.TriggerAvail(CP: TObject; Count: Word); | |
var i: Word; | |
begin | |
for i := 1 to Count do | |
sserial := sserial + serialPort.GetChar; | |
end; | |
procedure TNEAT300.ParseReturnedString; | |
var bFirstComma, bSecondComma: boolean; | |
i: integer; | |
c: Char; | |
begin | |
bFirstComma := False; bSecondComma := False; | |
s1 := ''; s2 := ''; s3 := ''; | |
if Length(sSerial) > 1 then | |
for i := 1 to Length(sSerial) do | |
begin | |
{parses the incoming strings by removing commas that separate values} | |
c := sSerial[i]; | |
if c = ',' then | |
begin | |
if not bFirstComma then | |
bFirstComma := True | |
else if not bSecondComma then | |
bSecondComma := True; | |
end | |
else if not (Ord(c) in [0..31]) and (c <> 'F') and (c <> '>') and (c in ['0'..'9','+','-']) then | |
begin | |
if not bFirstComma then | |
s1 := s1 + c | |
else if bFirstComma and not bSecondComma then | |
s2 := s2 + c | |
else | |
s3 := s3 + c; | |
end; | |
end; | |
end; | |
procedure TNEAT300.TimerReceived(CP: TObject; TriggerHandle: Word); | |
begin | |
sSerial := ''; | |
bNoAnswer := True; | |
fDeviceState := dsNotFound; | |
fBusy := False; | |
end; | |
procedure TNEAT300.SetSpeed(value: integer); | |
begin | |
if fBusy then Exit; | |
if value < 1 then value := 1; if value > 20 then value := 20; | |
inherited SetSpeed(value); | |
fBusy := True; | |
neatStatus := neatSETSPEED; | |
sSerial := ''; | |
serialPort.PutString('VI ' + IntToStr(value * 2000) + ',' + IntToStr(value * 2000) + CRLF); | |
repeat | |
Application.ProcessMessages; | |
until neatStatus = neatOK; | |
end; | |
procedure TNEAT300.GetXY(var newX, newY: integer); | |
begin | |
// if fBusy then Exit; | |
pNewX := @newX; | |
pNewY := @newY; | |
fBusy := True; | |
neatStatus := neatREAD; | |
sSerial := ''; | |
serialPort.PutString('RE' + CRLF); | |
end; | |
procedure TNEAT300.SetXY(var newX, newY: integer); | |
var curX, curY, deltaX, deltaY: integer; | |
begin | |
// if fBusy then Exit; | |
pNewX := @newX; | |
pNewY := @newY; | |
desiredX := newX; | |
desiredY := newY; | |
inherited SetXY(newX, newY); | |
ReadXY(curX, curY); | |
deltaX := Muldiv(10000, newX - curX, MICRONS_PER_STEP); | |
deltaY := Muldiv(10000, newY - curY, MICRONS_PER_STEP); | |
iterationCount := 0; | |
fBusy := True; | |
{ if not bFinePrecision then | |
neatStatus := neatMOVE | |
else} | |
neatStatus := neatMOVECLOSELOOP; | |
sSerial := ''; | |
serialPort.PutString('MR' + IntToStr(deltaX) + ',' + IntToStr(deltaY) + CRLF); | |
end; | |
procedure TNEAT300.SetRelativeXY(deltaX, deltaY: integer); | |
begin | |
if fBusy then Exit; | |
inherited SetRelativeXY(deltaX, deltaY); | |
{ fCallback := callback; | |
deltaX := Muldiv(10000, deltaX, MICRONS_PER_STEP); | |
deltaY := Muldiv(10000, deltaY, MICRONS_PER_STEP); | |
pNewX := @fXPosition; | |
pNewY := @fYPosition; | |
fBusy := True; | |
neatStatus := neatMOVE; | |
sSerial := ''; | |
serialPort.PutString('MR' + IntToStr(deltaX) + ',' + IntToStr(deltaY) + CRLF);} | |
ShiftByXY(deltaX, deltaY); | |
end; | |
procedure TNEAT300.MoveToXY(newX, newY: integer); | |
begin | |
if deviceStatus <> dsDetected then Exit; | |
inherited MoveToXY(newX, newY); | |
SetXY(newX, newY); | |
repeat | |
Application.ProcessMessages; | |
until neatStatus = neatOK; | |
end; | |
procedure TNEAT300.ReadXY(var x, y: integer); | |
begin | |
if deviceStatus <> dsDetected then Exit; | |
GetXY(x, y); | |
repeat | |
Application.ProcessMessages; | |
until neatStatus = neatOK; | |
end; | |
procedure TNEAT300.ShiftByXY(deltaX, deltaY: integer); | |
var x, y: integer; | |
begin | |
if deviceStatus <> dsDetected then Exit; | |
ReadXY(x, y); | |
if InvertX then deltaX := - deltaX; | |
if InvertY then deltaY := - deltaY; | |
x := deltaX + x; | |
y := deltaY + y; | |
SetXY(x, y); | |
end; | |
procedure TNEAT300.XYCommand(const sCommand: string); | |
begin | |
if fBusy then Exit; | |
fBusy := True; | |
neatStatus := neatCOMMAND; | |
sSerial := ''; | |
serialPort.PutString(sCommand + CRLF); | |
repeat | |
Application.ProcessMessages; | |
until neatStatus = neatOK; | |
end; | |
procedure TNEAT300.Connect; | |
begin | |
try | |
with serialPort do | |
begin | |
Baud := COMSpeed; | |
COMNumber := COMPort; | |
Parity := pNone; | |
DataBits := 8; | |
StopBits := 1; | |
sSerial := ''; | |
serialPort.Open := True; | |
CaretTriggerHandle := AddDataTrigger('>', False); | |
FTriggerHandle := AddDataTrigger('F', False); | |
TimerHandle := AddTimerTrigger; | |
OnTriggerData := TriggerData; | |
OnTriggerAvail := TriggerAvail; | |
OnTriggerTimer := TimerReceived; | |
end; | |
try | |
{We open the serial port and find out if the 'TERM3' command | |
returns with '>'. If not, timer event occurs and sets bNoAnswer} | |
{64 * 55 ms time out} | |
serialPort.SetTimerTrigger(TimerHandle, 64, True); | |
neatStatus := neatTERM3; | |
bNoAnswer := False; | |
fBusy := True; | |
serialPort.PutString('TERM3' + CRLF); | |
repeat | |
Application.ProcessMessages; | |
until (neatStatus = neatOK) or bNoAnswer; | |
except | |
fDeviceState := dsNotFound; | |
end; | |
except | |
fDeviceState := dsNotFound; | |
end; | |
end; | |
constructor TNEAT300.Create; | |
begin | |
inherited Create; | |
name := 'Danaher NEAT 300 X-Y Table'; | |
serialPort := TApdCOMPort.Create(nil); | |
serialPort.AutoOpen := False; | |
end; | |
destructor TNEAT300.Destroy; | |
begin | |
serialPort.Free; | |
inherited Destroy; | |
end; | |
{***************************** TXYMP285 *******************************} | |
function TXYMP285.GetDeviceState: TDeviceState; | |
begin | |
Result := xyzMP285.GetDeviceState; | |
end; | |
procedure TXYMP285.SetSpeed(value: integer); | |
begin | |
xyzMP285.SetSpeed(value); | |
end; | |
procedure TXYMP285.Connect; | |
begin | |
xyzMP285.Connect; | |
end; | |
procedure TXYMP285.GetXY(var newX, newY: integer); | |
begin | |
inherited GetXY(newX, newY); | |
xyzMP285.GetXYZ; | |
newX := xyTable.fXPosition; | |
newY := xyTable.fYPosition; | |
Mainform.UpdateXYCaptions; | |
end; | |
procedure TXYMP285.SetXY(var newX, newY: integer); | |
begin | |
inherited SetXY(newX, newY); | |
xyzMP285.SetXYZ(newX, newY, zStepper.fZPosition); | |
end; | |
procedure TXYMP285.SetRelativeXY(deltaX, deltaY: integer); | |
begin | |
if not fBusy then | |
begin | |
{updates current position} | |
xyzMP285.GetXYZ; | |
inherited SetRelativeXY(deltaX, deltaY); | |
xyTable.fXPosition := xyTable.fXPosition + deltaX; | |
xyTable.fYPosition := xyTable.fYPosition + deltaY; | |
fBusy := True; | |
xyzMP285.SetXYZ(xyTable.fXPosition, xyTable.fYPosition, ZStepper.ZPosition); | |
end; | |
end; | |
procedure TXYMP285.MoveToXY(newX, newY: integer); | |
begin | |
inherited MoveToXY(newX, newY); | |
xyzMP285.SetXYZ(newX, newY, zStepper.fZPosition); | |
end; | |
procedure TXYMP285.ReadXY(var x, y: integer); | |
begin | |
inherited ReadXY(x, y); | |
xyzMP285.GetXYZ; | |
x := xyTable.XPosition; | |
y := xyTable.YPosition; | |
end; | |
procedure TXYMP285.ShiftByXY(deltaX, deltaY: integer); | |
begin | |
inherited ShiftByXY(deltaX, deltaY); | |
xyzMP285.SetXYZ(xyTable.fXPosition + deltaX, xyTable.fYPosition + deltaY, zStepper.fZPosition); | |
end; | |
procedure TXYMP285.XYCommand(const sCommand: string); | |
begin | |
xyzMP285.XYCommand(sCommand); | |
end; | |
constructor TXYMP285.Create; | |
begin | |
inherited Create; | |
name := 'Sutter MP-285 X-Y Table'; | |
xyzMP285 := TXYZMP285.Create; | |
{ xyzMP285.SetResolutionToLow;} | |
end; | |
destructor TXYMP285.Destroy; | |
begin | |
FreeAndNil(xyzMP285); | |
inherited Destroy; | |
end; | |
{********************************* XYESP300 ***********************************} | |
function TXYESP300.GetDeviceState: TDeviceState; | |
begin | |
Result := xyzESP300.GetDeviceState; | |
end; | |
procedure TXYESP300.SetSpeed(value: integer); | |
begin | |
inherited SetSpeed(value); | |
xyzESP300.SetXYSpeed(value); | |
end; | |
procedure TXYESP300.Connect; | |
begin | |
xyzESP300.Connect; | |
end; | |
procedure TXYESP300.GetXY(var newX, newY: integer); | |
begin | |
xyzESP300.GetXY(newX, newY); | |
end; | |
procedure TXYESP300.SetXY(var newX, newY: integer); | |
begin | |
xyzESP300.SetXY(newX, newY); | |
end; | |
procedure TXYESP300.SetRelativeXY(deltaX, deltaY: integer); | |
begin | |
if InvertX then deltaX := - deltaX; | |
if InvertY then deltaY := - deltaY; | |
xyzESP300.SetRelativeXY(deltaX, deltaY); | |
end; | |
procedure TXYESP300.MoveToXY(newX, newY: integer); | |
begin | |
xyzESP300.MoveToXY(newX, newY); | |
end; | |
procedure TXYESP300.ReadXY(var x, y: integer); | |
begin | |
inherited ReadXY(x, y); | |
xyzESP300.ReadXY(x, y); | |
end; | |
procedure TXYESP300.ShiftByXY(deltaX, deltaY: integer); | |
begin | |
if InvertX then deltaX := - deltaX; | |
if InvertY then deltaY := - deltaY; | |
xyzESP300.ShiftByXY(deltaX, deltaY); | |
end; | |
procedure TXYESP300.XYCommand(const sCommand: string); | |
begin | |
xyzESP300.XYCommand(sCommand); | |
end; | |
constructor TXYESP300.Create; | |
begin | |
inherited Create; | |
name := 'Newport ESP300 X-Y Table'; | |
COMSpeed := 19200; | |
xyzESP300 := TXYZESP300.Create; | |
end; | |
destructor TXYESP300.Destroy; | |
begin | |
xyzESP300.Free; | |
inherited Destroy; | |
end; | |
{********************************* TZESP300 ***********************************} | |
function TZESP300.GetDeviceState: TDeviceState; | |
begin | |
Result := xyzESP300.GetDeviceState; | |
end; | |
procedure TZESP300.Connect; | |
begin | |
xyzESP300.Connect; | |
end; | |
procedure TZESP300.SetSpeed(speedIndex: integer); | |
begin | |
xyzESP300.SetZSpeed(speedIndex); | |
end; | |
procedure TZESP300.GetZ(var newZ: double); | |
begin | |
xyzESP300.GetZ(newZ); | |
end; | |
procedure TZESP300.MoveToRelativeZ(newDeltaZ: double); | |
begin | |
xyzESP300.MoveToRelativeZ(newDeltaZ); | |
end; | |
procedure TZESP300.SetZ(var newZ: double); | |
begin | |
xyzESP300.SetZ(newZ); | |
end; | |
procedure TZESP300.MoveToZ(newZ: double); | |
begin | |
xyzESP300.MoveToZ(newZ); | |
end; | |
function TZESP300.ReadZ: double; | |
begin | |
Result := xyzESP300.ReadZ; | |
end; | |
procedure TZESP300.ShiftByZ(deltaZ: double); | |
begin | |
xyzESP300.ShiftByZ(deltaZ); | |
end; | |
function TZESP300.TravelTime(zTravel: integer; speedIndex: integer): double; | |
begin | |
Result := 5 {step /micron} * Abs(zTravel) * (80 - speedIndex) / 1000; | |
end; | |
procedure ZESP300FastStackCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; | |
var newPower: integer; | |
currentDisplacement: double; | |
begin | |
with TZMP285(dwUser) do | |
begin | |
if not Odd(curFastRepeatCount) and (Mainform.Configuration.zDistance < 0) then | |
fZPosition := fZPosition - stepSize | |
else | |
fZPosition := fZPosition + stepSize; | |
xyzESP300.MoveToZ(fZPosition); | |
{Adjust laser power here} | |
with Mainform.Configuration, Mainform.engine do | |
if IntensityControl <> IC_NO_CONTROL then | |
begin | |
currentDisplacement := - startFastScanPosition + fZPosition; | |
if IntensityControl = IC_LINEAR then | |
newPower := Round(currentDisplacement * (FinalIntensity - InitialIntensity)/AtZDistance | |
+ InitialIntensity) | |
else | |
begin | |
if InitialIntensity <= 0 then InitialIntensity := 1; | |
newPower := Round(InitialIntensity * | |
exp(currentDisplacement * Ln(FinalIntensity/InitialIntensity) / AtZDistance)); | |
end; | |
if Abs(newPower - LaserControl.Power) > 0 then | |
begin | |
analogOutputBoard.AnalogOut(1, newPower/10); | |
LaserControl.Power := newPower; | |
end; | |
end; | |
if (ZPosition = startFastScanPosition + Mainform.Configuration.zDistance) or | |
(ZPosition = startFastScanPosition) then | |
begin | |
curFastRepeatCount := curFastRepeatCount + 1; | |
if curFastRepeatCount >= Mainform.Configuration.FastStackRepeatCount then | |
begin | |
if bTimerActive then timeKillEvent(zTimer); | |
bTimerActive := False; | |
bFastScanInProgress := False; | |
PostMessage(Mainform.Handle, WM_FASTSTACK_ENDED, 0, 0); | |
end; | |
end; | |
end; | |
end; | |
procedure TZESP300.StartFastScan; | |
begin | |
inherited StartFastScan; | |
GetZ(startFastScanPosition); {we get the initial position} | |
with Mainform.configuration do | |
begin | |
curFastRepeatCount := 0; | |
{The timer is set to fire every 80 - TravelSpeed millisecond} | |
bTimerActive := True; | |
zTimer := timeSetEvent(80 - TravelSpeed, 0, ZESP300FastStackCallback, DWORD(self), TIME_PERIODIC); | |
end; | |
end; | |
procedure TZESP300.StopFastScan; | |
begin | |
if not bFastScanInProgress then Exit; | |
if bTimerActive then timeKillEvent(zTimer); | |
bTimerActive := False; | |
inherited StopFastScan; | |
end; | |
constructor TZESP300.Create; | |
begin | |
inherited Create; | |
name := 'Newport ESP300 Z-Stepper'; | |
{ fSpeed := 5;} {medium speed} | |
fStepSize := 0.2; {0.2 microns / step} | |
end; | |
destructor TZESP300.Destroy; | |
begin | |
inherited Destroy; | |
end; | |
{******************************* TXYZESP300 ***********************************} | |
procedure TXYZESP300.TriggerData(CP: TObject; TriggerHandle: Word); | |
begin | |
serialPort.SetTimerTrigger(TimerHandle, 256, False); | |
if TriggerHandle <> CRTriggerHandle then Exit; | |
try | |
case fESPMode of | |
ESP300_READING_X: lastX := StrToFloat(sserial); | |
ESP300_READING_Y: lastY := StrToFloat(sserial); | |
ESP300_READING_Z: lastZ := StrToFloat(sserial); | |
end; | |
except | |
bMovingError := True; | |
end; | |
bReading := False; | |
sSerial := ''; | |
end; | |
procedure TXYZESP300.TriggerAvail(CP: TObject; Count: Word); | |
var i: Word; | |
begin | |
for i := 1 to Count do | |
sserial := sserial + serialPort.GetChar; | |
end; | |
procedure TXYZESP300.TimerReceived(CP: TObject; TriggerHandle: Word); | |
begin | |
if TriggerHandle = TimerHandle then | |
begin | |
sSerial := ''; | |
bReading := False; | |
fDeviceState := dsNotFound; | |
end; | |
end; | |
procedure TXYZESP300.Connect; | |
begin | |
inherited Connect; | |
try | |
with serialPort do | |
begin | |
Baud := XYTable.COMSpeed; | |
COMNumber := XYTable.COMPort; | |
Parity := pNone; | |
DataBits := 8; | |
StopBits := 1; | |
sSerial := ''; | |
serialPort.Open := True; | |
CRTriggerHandle := AddDataTrigger(Chr(13)+Chr(10), False); | |
TimerHandle := AddTimerTrigger; | |
OnTriggerData := TriggerData; | |
OnTriggerAvail := TriggerAvail; | |
OnTriggerTimer := TimerReceived; | |
end; | |
try | |
fBusy := True; | |
{Unit for each axis: micron, encoder resolution: 0.2 micron} | |
{256 * 55 ms time out} | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
bReading := True; fESPMode := ESP300_COMMAND; | |
serialPort.PutString('1SN3' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
bReading := True; fESPMode := ESP300_COMMAND; | |
serialPort.PutString('2SN3' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
bReading := True; fESPMode := ESP300_COMMAND; | |
serialPort.PutString('3SN3' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
bReading := True; fESPMode := ESP300_COMMAND; | |
serialPort.PutString('1SU0.2' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
bReading := True; fESPMode := ESP300_COMMAND; | |
serialPort.PutString('2SU0.2' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
bReading := True; fESPMode := ESP300_COMMAND; | |
serialPort.PutString('3SU0.2' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
{Let's get the max velocities for each axis} | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
bReading := True; fEspMode := ESP300_READING_X; | |
serialPort.PutString('1VU?' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
if not bMovingError then maxVelocityX := lastX; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
bReading := True; fEspMode := ESP300_READING_Y; | |
serialPort.PutString('2VU?' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
if not bMovingError then maxVelocityY := lastY; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
bReading := True; fEspMode := ESP300_READING_Z; | |
serialPort.PutString('3VU?' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
if not bMovingError then maxVelocityZ := lastZ; | |
fDeviceState := dsDetected; | |
except | |
fDeviceState := dsNotFound; | |
end; | |
except | |
fDeviceState := dsNotFound; | |
end; | |
end; | |
procedure TXYZESP300.SetZSpeed(speedIndex: integer); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
fESPMode := ESP300_COMMAND; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('3VA' + Format('%.1f', [speedIndex * maxVelocityZ / 20]) + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
end; | |
procedure TXYZESP300.SetXYSpeed(speedIndex: integer); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
fESPMode := ESP300_COMMAND; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('1VA' + Format('%.1f', [speedIndex * maxVelocityX / 20]) + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_COMMAND; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('2VA' + Format('%.1f', [speedIndex * maxVelocityY / 20]) + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
end; | |
procedure TXYZESP300.GetZ(var newZ: double); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
bReading := True; | |
fESPMode := ESP300_READING_Z; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('3TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
ZStepper.fZPosition := lastZ; | |
end; | |
procedure TXYZESP300.MoveToRelativeZ(newDeltaZ: double); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
fBusy := True; | |
zStepper.OnMoveStarted; | |
fESPMode := ESP300_COMMAND; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('3PR' + Format('%.1f', [newDeltaZ]) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('3WS0'); | |
bReading := True; | |
fESPMode := ESP300_READING_Z; | |
serialPort.PutString('3TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
ZStepper.fZPosition := lastZ; | |
zStepper.OnMoveFinished; | |
fBusy := False; | |
end; | |
procedure TXYZESP300.SetZ(var newZ: double); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
fBusy := True; | |
zStepper.OnMoveStarted; | |
fESPMode := ESP300_COMMAND; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('3PA' + Format('%.1f', [newZ]) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('3WS0'); | |
bReading := True; | |
fESPMode := ESP300_READING_Z; | |
serialPort.PutString('3TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
ZStepper.fZPosition := lastZ; | |
fBusy := False; | |
end; | |
procedure TXYZESP300.MoveToZ(newZ: double); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
fBusy := True; | |
fESPMode := ESP300_COMMAND; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('3PA' + Format('%.1f', [newZ]) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('3WS0'); | |
bReading := True; | |
fESPMode := ESP300_READING_Z; | |
serialPort.PutString('3TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
ZStepper.fZPosition := lastZ; | |
ZStepper.OnMoveFinished; | |
fBusy := False; | |
end; | |
function TXYZESP300.ReadZ: double; | |
begin | |
if fBusy then | |
Result := 0 | |
else | |
begin | |
bMovingError := False; | |
bReading := True; | |
fESPMode := ESP300_READING_Z; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('3TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
ZStepper.fZPosition := lastZ; | |
Result := lastZ; | |
end; | |
end; | |
procedure TXYZESP300.ShiftByZ(deltaZ: double); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
fBusy := True; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('3PR' + Format('%.1f', [deltaZ]) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('3WS0'); | |
bReading := True; | |
fESPMode := ESP300_READING_Z; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('3TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
ZStepper.fZPosition := lastZ; | |
ZStepper.OnMoveFinished; | |
fBusy := False; | |
end; | |
procedure TXYZESP300.GetXY(var newX, newY: integer); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
bReading := True; | |
fESPMode := ESP300_READING_X; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('1TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fXPosition := Round(lastX); | |
bReading := True; | |
fESPMode := ESP300_READING_Y; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('2TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fYPosition := Round(lastY); | |
end; | |
procedure TXYZESP300.SetXY(var newX, newY: integer); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
fBusy := True; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('1PA' + IntToStr(newX) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('2PA' + IntToStr(newY) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('1WS0'); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('2WS0'); | |
bReading := True; | |
fESPMode := ESP300_READING_X; | |
serialPort.PutString('1TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fXPosition := Round(lastX); | |
bReading := True; | |
fESPMode := ESP300_READING_Y; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('2TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fYPosition := Round(lastY); | |
XYTable.OnMoveFinished; | |
fBusy := False; | |
end; | |
procedure TXYZESP300.SetRelativeXY(deltaX, deltaY: integer); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
xyTable.OnMoveStarted; | |
fBusy := True; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('1PR' + IntToStr(deltaX) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('2PR' + IntToStr(deltaY) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('1WS0'); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('2WS0'); | |
bReading := True; | |
fESPMode := ESP300_READING_X; | |
serialPort.PutString('1TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fXPosition := Round(lastX); | |
bReading := True; | |
fESPMode := ESP300_READING_Y; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('2TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fYPosition := Round(lastY); | |
XYTable.OnMoveFinished; | |
fBusy := False; | |
end; | |
procedure TXYZESP300.MoveToXY(newX, newY: integer); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
fBusy := True; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('1PA' + IntToStr(newX) + Chr(13)); | |
serialPort.PutString('2PA' + IntToStr(newY) + Chr(13)); | |
serialPort.PutString('1WS0'); | |
serialPort.PutString('2WS0'); | |
bReading := True; | |
fESPMode := ESP300_READING_X; | |
serialPort.PutString('1TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fXPosition := Round(lastX); | |
bReading := True; | |
fESPMode := ESP300_READING_Y; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('2TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fYPosition := Round(lastY); | |
XYTable.OnMoveFinished; | |
fBusy := False; | |
end; | |
procedure TXYZESP300.ReadXY(var x, y: integer); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
bReading := True; | |
fESPMode := ESP300_READING_X; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('1TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fXPosition := Round(lastX); | |
bReading := True; | |
fESPMode := ESP300_READING_Y; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('2TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fYPosition := Round(lastY); | |
x := Round(lastX); y := Round(lastY); | |
end; | |
procedure TXYZESP300.ShiftByXY(deltaX, deltaY: integer); | |
begin | |
if fBusy then Exit; | |
bMovingError := False; | |
fBusy := True; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('1PR' + IntToStr(deltaX) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('2PR' + IntToStr(deltaY) + Chr(13)); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('1WS0'); | |
fESPMode := ESP300_COMMAND; | |
serialPort.PutString('2WS0'); | |
bReading := True; | |
fESPMode := ESP300_READING_X; | |
serialPort.PutString('1TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fXPosition := Round(lastX); | |
bReading := True; | |
fESPMode := ESP300_READING_Y; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('2TP' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
XYTable.fYPosition := Round(lastY); | |
XYTable.OnMoveFinished; | |
fBusy := False; | |
end; | |
procedure TXYZESP300.XYCommand(const sCommand: string); | |
begin | |
if fESPMode <> ESP300_READY then Exit; | |
bReading := True; | |
fESPMode := ESP300_COMMAND; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString(sCommand + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until not bReading; | |
fESPMode := ESP300_READY; | |
end; | |
constructor TXYZESP300.Create; | |
begin | |
inherited Create; | |
serialPort := TApdCOMPort.Create(nil); | |
serialPort.AutoOpen := False; | |
end; | |
destructor TXYZESP300.Destroy; | |
begin | |
serialPort.Free; | |
inherited Destroy; | |
end; | |
{***************************** MICROMANIPULATOR *******************************} | |
procedure TMicromanipulator.FindDescentPosition(var descentPos: TMManPt); | |
var mmanTarget: TMManPt; | |
begin | |
XYZToManipulator(xyzTargetPt, mmanTarget); | |
{descent pos is startDescentDistance away from target, at angle approachAngle | |
in the X-Z or Y-Z plane} | |
if AxialIsXZ then | |
begin | |
descentPos[mmanX] := mmanTarget[mmanX] - cos(2*pi*approachAngle/360) * startDescentDistance; | |
descentPos[mmanY] := mmanTarget[mmanY]; | |
end | |
else | |
begin | |
descentPos[mmanY] := mmanTarget[mmanY] - cos(2*pi*approachAngle/360) * startDescentDistance; | |
descentPos[mmanX] := mmanTarget[mmanX]; | |
end; | |
descentPos[mmanZ] := mmanTarget[mmanZ] + sin(2*pi*approachAngle/360) * startDescentDistance; | |
end; | |
function TMicromanipulator.GetApproachAngle: double; | |
begin | |
Result := approachAngles[fmanIndex]; | |
end; | |
function TMicromanipulator.GetApproachSpeed: integer; | |
begin | |
Result := approachSpeeds[fmanIndex]; | |
end; | |
function TMicromanipulator.GetAxialIsXZ: boolean; | |
begin | |
Result := axialIsXZs[fmanIndex]; | |
end; | |
function TMicromanipulator.GetCalibrationShift: integer; | |
begin | |
Result := calibrationShifts[fmanIndex]; | |
end; | |
function TMicromanipulator.GetCoarseMotion: boolean; | |
begin | |
Result := True; | |
end; | |
function TMicromanipulator.GetCOMPort: integer; | |
begin | |
Result := mmCOMPortIndex[fmanIndex]; | |
end; | |
function TMicromanipulator.GetCOMSpeed: integer; | |
begin | |
Result := mmCOMSpeedIndex[fmanIndex]; | |
end; | |
function TMicromanipulator.GetContactSpeed: integer; | |
begin | |
Result := contactSpeeds[fmanIndex]; | |
end; | |
function TMicromanipulator.GetContactStepSize: double; | |
begin | |
Result := contactStepSizes[fmanIndex]; | |
end; | |
function TMicromanipulator.GetDescentSpeed: integer; | |
begin | |
Result := descentSpeeds[fmanIndex]; | |
end; | |
function TMicromanipulator.GetInvertX: boolean; | |
begin | |
Result := bmmInvertX[fmanIndex]; | |
end; | |
function TMicromanipulator.GetInvertY: boolean; | |
begin | |
Result := bmmInvertY[fmanIndex]; | |
end; | |
function TMicromanipulator.GetInvertZ: boolean; | |
begin | |
Result := bmmInvertZ[fmanIndex]; | |
end; | |
function TMicromanipulator.GetmmReadDelay: integer; | |
begin | |
Result := fmmReadDelay; | |
end; | |
function TMicromanipulator.GetFirstMotionType: TMManCoordinates; | |
begin | |
Result := firstMotionTypes[fmanIndex]; | |
end; | |
function TMicromanipulator.GetSecondMotionType: TMManCoordinates; | |
begin | |
Result := secondMotionTypes[fmanIndex]; | |
end; | |
function TMicromanipulator.GetThirdMotionType: TMManCoordinates; | |
begin | |
Result := thirdMotionTypes[fmanIndex]; | |
end; | |
function TMicromanipulator.GetstartDescentDistance: double; | |
begin | |
Result := startDescentDistances[fmanIndex]; | |
end; | |
function TMicromanipulator.GetstopDescentDistance: double; | |
begin | |
Result := stopDescentDistances[fmanIndex]; | |
end; | |
function TMicromanipulator.GetxyzReadDelay: integer; | |
begin | |
Result := fxyzReadDelay; | |
end; | |
procedure TMicromanipulator.SetApproachAngle(value: double); | |
begin | |
if (value > 0) and (value < 90) then | |
approachAngles[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetApproachSpeed(value: integer); | |
begin | |
if (value > 0) and (value <= 2900) then | |
approachSpeeds[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetAxialIsXZ(value: boolean); | |
begin | |
axialIsXZs[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetCalibrationShift(value: integer); | |
begin | |
calibrationShifts[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetCoarseMotion(value: boolean); | |
begin | |
end; | |
procedure TMicromanipulator.SetCOMPort(value: integer); | |
begin | |
mmCOMPortIndex[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetCOMSpeed(value: integer); | |
begin | |
mmCOMSpeedIndex[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetContactSpeed(value: integer); | |
begin | |
contactSpeeds[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetContactStepSize(value: double); | |
begin | |
contactStepSizes[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetDescentSpeed(value: integer); | |
begin | |
descentSpeeds[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetInvertX(value: boolean); | |
begin | |
bmmInvertX[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetInvertY(value: boolean); | |
begin | |
bmmInvertY[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetInvertZ(value: boolean); | |
begin | |
bmmInvertZ[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetmmReadDelay(value: integer); | |
begin | |
fmmReadDelay := value; | |
end; | |
procedure TMicromanipulator.SetFirstMotionType(value: TMManCoordinates); | |
begin | |
firstMotionTypes[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetSecondMotionType(value: TMManCoordinates); | |
begin | |
secondMotionTypes[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetThirdMotionType(value: TMManCoordinates); | |
begin | |
thirdMotionTypes[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetxyzReadDelay(value: integer); | |
begin | |
fxyzReadDelay := value; | |
end; | |
procedure TMicromanipulator.SetstartDescentDistance(value: double); | |
begin | |
startDescentDistances[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.SetstopDescentDistance(value: double); | |
begin | |
stopDescentDistances[fmanIndex] := value; | |
end; | |
procedure TMicromanipulator.XYZToManipulator(xyzPt: TXYZPt; var manPt: TMManPt); | |
var vector: TXYZPt; | |
begin | |
vector[mmanX] := xyzPt[mmanX] - xyzCalibrationPts[0][mmanX]; | |
vector[mmanY] := xyzPt[mmanY] - xyzCalibrationPts[0][mmanY]; | |
vector[mmanZ] := xyzPt[mmanZ] - xyzCalibrationPts[0][mmanZ]; | |
{rotates vector} | |
manPt[mmanX] := calibMatrix[0,0] * vector[mmanX] + calibMatrix[1,0] * vector[mmanY] + calibMatrix[2,0] * vector[mmanZ]; | |
manPt[mmanY] := calibMatrix[0,1] * vector[mmanX] + calibMatrix[1,1] * vector[mmanY] + calibMatrix[2,1] * vector[mmanZ]; | |
manPt[mmanZ] := calibMatrix[0,2] * vector[mmanX] + calibMatrix[1,2] * vector[mmanY] + calibMatrix[2,2] * vector[mmanZ]; | |
{changes origin} | |
manPt[mmanX] := manPt[mmanX] + mmanCalibrationPts[0][mmanX]; | |
manPt[mmanY] := manPt[mmanY] + mmanCalibrationPts[0][mmanY]; | |
manPt[mmanZ] := manPt[mmanZ] + mmanCalibrationPts[0][mmanZ]; | |
end; | |
procedure TMicromanipulator.Calibrate; | |
var deltas: array[1..3] of TXYZPt; | |
i: integer; | |
j: TMManCoordinates; | |
aXY23, aXZ21, aXY21, aXZ23, delta: double; | |
begin | |
for i := 1 to 3 do | |
for j := mmanX to mmanZ do | |
deltas[i, j] := xyzCalibrationPts[i, j] - xyzCalibrationPts[0, j]; | |
aXY23 := deltas[2][mmanX] * deltas[3][mmanY] - deltas[3][mmanX] * deltas[2][mmanY]; | |
aXZ21 := deltas[2][mmanX] * deltas[1][mmanZ] - deltas[1][mmanX] * deltas[2][mmanZ]; | |
aXY21 := deltas[2][mmanX] * deltas[1][mmanY] - deltas[1][mmanX] * deltas[2][mmanY]; | |
aXZ23 := deltas[2][mmanX] * deltas[3][mmanZ] - deltas[3][mmanX] * deltas[2][mmanZ]; | |
delta := aXZ21 * aXY23 - aXZ23 * aXY21; | |
calibMatrix[2,0] := aXY23 * calibrationShift * deltas[2][mmanX] / delta; | |
calibMatrix[1,0] := (calibrationShift * deltas[2][mmanX] - aXZ21 * calibMatrix[2,0]) / aXY21; | |
calibMatrix[0,0] := (calibrationShift - calibMatrix[1,0] * deltas[1][mmanY] - calibMatrix[2,0] * deltas[1][mmanZ]) / deltas[1][mmanX]; | |
calibMatrix[2,1] := - aXY21 * calibrationShift * deltas[3][mmanX] / delta; | |
calibMatrix[1,1] := - aXZ21 * calibMatrix[2,1] / aXY21; | |
calibMatrix[0,1] := - (calibMatrix[1,1] * deltas[1][mmanY] + calibMatrix[2,1] * deltas[1][mmanZ]) / deltas[1][mmanX]; | |
calibMatrix[2,2] := - aXY21 * calibrationShift * deltas[2][mmanX] / delta; | |
calibMatrix[1,2] := - aXZ21 * calibMatrix[2,2] / aXY21; | |
calibMatrix[0,2] := - (calibMatrix[1,2] * deltas[1][mmanY] + calibMatrix[2,2] * deltas[1][mmanZ]) / deltas[1][mmanX]; | |
if Phase = mpTargeted then Phase := mpTargeted_Calibrated else | |
Phase := mpCalibrated; | |
end; | |
procedure TMicromanipulator.ContactMoveDown(bDown: boolean); | |
var targetPos, vector, nextPos: TMManPt; | |
distance: double; | |
begin | |
{We move towards or away from the target in the X-Y-Z axis from our current position | |
by contactStepSize increment} | |
GetCurrentMMPosition; | |
XYZToManipulator(xyzTargetPt, targetPos); | |
distance := FindDistance(currentPos, targetPos); | |
if (distance < 0.01) and bDown then Exit; {0.01 microns minimal distance: bail!} | |
vector[mmanX] := contactStepSize * (targetPos[mmanX] - currentPos[mmanX]) / distance; | |
vector[mmanY] := contactStepSize * (targetPos[mmanY] - currentPos[mmanY]) / distance; | |
vector[mmanZ] := contactStepSize * (targetPos[mmanX] - currentPos[mmanZ]) / distance; | |
if bDown then | |
begin | |
nextPos[mmanX] := currentPos[mmanX] + vector[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY] + vector[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ] + vector[mmanZ]; | |
end | |
else | |
begin | |
nextPos[mmanX] := currentPos[mmanX] - vector[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY] - vector[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ] - vector[mmanZ]; | |
end; | |
MoveAndWait(nextPos); | |
end; | |
procedure TMicromanipulator.GetCurrentMMPosition; | |
begin | |
GetXYZ; | |
repeat | |
Application.ProcessMessages; | |
until mmanOp = mmanOK; | |
end; | |
procedure TMicromanipulator.GoHome; | |
var nextPos, newPos: TMManPt; | |
begin | |
{3rd motion} | |
GetCurrentMMPosition; | |
if thirdMotionType = mmanX then | |
begin | |
nextPos[mmanX] := homePt[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ]; | |
end | |
else if thirdMotionType = mmanY then | |
begin | |
nextPos[mmanX] := currentPos[mmanX]; | |
nextPos[mmanY] := homePt[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ]; | |
end | |
else | |
begin | |
nextPos[mmanX] := currentPos[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY]; | |
nextPos[mmanZ] := homePt[mmanZ]; | |
end; | |
MoveAndWait(nextPos); | |
newPos := currentPos; | |
{2nd motion} | |
if secondMotionType = mmanX then | |
begin | |
nextPos[mmanX] := homePt[mmanX]; | |
nextPos[mmanY] := newPos[mmanY]; | |
nextPos[mmanZ] := newPos[mmanZ]; | |
end | |
else if secondMotionType = mmanY then | |
begin | |
nextPos[mmanX] := newPos[mmanX]; | |
nextPos[mmanY] := homePt[mmanY]; | |
nextPos[mmanZ] := newPos[mmanZ]; | |
end | |
else | |
begin | |
nextPos[mmanX] := newPos[mmanX]; | |
nextPos[mmanY] := newPos[mmanY]; | |
nextPos[mmanZ] := homePt[mmanZ]; | |
end; | |
MoveAndWait(nextPos); | |
newPos := currentPos; | |
{1st motion} | |
if firstMotionType = mmanX then | |
begin | |
nextPos[mmanX] := homePt[mmanX]; | |
nextPos[mmanY] := newPos[mmanY]; | |
nextPos[mmanZ] := newPos[mmanZ]; | |
end | |
else if firstMotionType = mmanY then | |
begin | |
nextPos[mmanX] := newPos[mmanX]; | |
nextPos[mmanY] := homePt[mmanY]; | |
nextPos[mmanZ] := newPos[mmanZ]; | |
end | |
else | |
begin | |
nextPos[mmanX] := newPos[mmanX]; | |
nextPos[mmanY] := newPos[mmanY]; | |
nextPos[mmanZ] := homePt[mmanZ]; | |
end; | |
MoveAndWait(nextPos); | |
end; | |
procedure TMicromanipulator.GotoDescentPos; | |
var mmanDescentPos: TMManPt; | |
begin | |
FindDescentPosition(mmanDescentPos); | |
GetCurrentMMPosition; | |
if (currentPos[mmanX] <> mmanDescentPos[mmanX]) or | |
(currentPos[mmanY] <> mmanDescentPos[mmanY]) or | |
(currentPos[mmanZ] <> mmanDescentPos[mmanZ]) | |
then | |
MoveAndWait(mmanDescentPos); | |
end; | |
procedure TMicromanipulator.GetXYZ; | |
begin | |
end; | |
procedure TMicromanipulator.MoveToXYZ(newX, newY, newZ: double); | |
begin | |
end; | |
procedure TMicromanipulator.MoveRelative(deltaX, deltaY, deltaZ: double); | |
var manPt: TMManPt; | |
begin | |
GetCurrentMMPosition; | |
if InvertX then deltaX := - deltaX; | |
if InvertY then deltaY := - deltaY; | |
if InvertZ then deltaZ := - deltaZ; | |
manPt[mmanX] := currentPos[mmanX] + deltaX; | |
manPt[mmanY] := currentPos[mmanY] + deltaY; | |
manPt[mmanZ] := currentPos[mmanZ] + deltaZ; | |
MoveAndWait(manPt); | |
end; | |
procedure TMicromanipulator.SetSpeed(value: integer); | |
begin | |
fSpeed := value; | |
end; | |
procedure TMicromanipulator.MoveAndWait(manPt: TMManPt); | |
var i: integer; | |
begin | |
with Mainform do | |
begin | |
Screen.Cursor := crHourGlass; | |
Shape5.Brush.Color := clRed; | |
Shape5.Refresh; | |
end; | |
MoveToXYZ(manPt[mmanX], manPt[mmanY], manPt[mmanZ]); | |
repeat | |
Application.ProcessMessages; | |
until mmanOp = mmanOK; | |
with Mainform do | |
begin | |
Shape5.Brush.Color := clLime; | |
Shape5.Refresh; | |
{MP-285 is a slow device - this loop adds a delay after a move} | |
for i := 1 to mmReadDelay do Application.ProcessMessages; | |
GetCurrentMMPosition; | |
UpdateMManCaptions; | |
Screen.Cursor := crDefault; | |
end; | |
end; | |
procedure TMicromanipulator.StartApproach; | |
var mmanDescentPos, nextPos: TMManPt; | |
begin | |
FindDescentPosition(mmanDescentPos); | |
{1st motion} | |
GetCurrentMMPosition; | |
if firstMotionType = mmanX then | |
begin | |
nextPos[mmanX] := mmanDescentPos[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ]; | |
end | |
else if firstMotionType = mmanY then | |
begin | |
nextPos[mmanX] := currentPos[mmanX]; | |
nextPos[mmanY] := mmanDescentPos[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ]; | |
end | |
else | |
begin | |
nextPos[mmanX] := currentPos[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY]; | |
nextPos[mmanZ] := mmanDescentPos[mmanZ]; | |
end; | |
MoveAndWait(nextPos); | |
{2nd motion} | |
if secondMotionType = mmanX then | |
begin | |
nextPos[mmanX] := mmanDescentPos[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ]; | |
end | |
else if secondMotionType = mmanY then | |
begin | |
nextPos[mmanX] := currentPos[mmanX]; | |
nextPos[mmanY] := mmanDescentPos[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ]; | |
end | |
else | |
begin | |
nextPos[mmanX] := currentPos[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY]; | |
nextPos[mmanZ] := mmanDescentPos[mmanZ]; | |
end; | |
MoveAndWait(nextPos); | |
{3rd motion} | |
if thirdMotionType = mmanX then | |
begin | |
nextPos[mmanX] := mmanDescentPos[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ]; | |
end | |
else if thirdMotionType = mmanY then | |
begin | |
nextPos[mmanX] := currentPos[mmanX]; | |
nextPos[mmanY] := mmanDescentPos[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ]; | |
end | |
else | |
begin | |
nextPos[mmanX] := currentPos[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY]; | |
nextPos[mmanZ] := mmanDescentPos[mmanZ]; | |
end; | |
MoveAndWait(nextPos); | |
end; | |
procedure TMicromanipulator.StartDescent; | |
var targetPos, vector, nextPos: TMManPt; | |
distance, newdistance: double; | |
begin | |
GotoDescentPos; {just to be on the safe side - we will be StartDescentDistance | |
away from targe} | |
GetCurrentMMPosition; | |
XYZToManipulator(xyzTargetPt, targetPos); | |
distance := FindDistance(currentPos, targetPos); {StartDescentDistance} | |
newdistance := distance - stopDescentDistance; | |
if newdistance < distance then | |
begin | |
vector[mmanX] := newdistance * (targetPos[mmanX] - currentPos[mmanX]) / distance; | |
vector[mmanY] := newdistance * (targetPos[mmanY] - currentPos[mmanY]) / distance; | |
vector[mmanZ] := newdistance * (targetPos[mmanX] - currentPos[mmanZ]) / distance; | |
nextPos[mmanX] := currentPos[mmanX] + vector[mmanX]; | |
nextPos[mmanY] := currentPos[mmanY] + vector[mmanY]; | |
nextPos[mmanZ] := currentPos[mmanZ] + vector[mmanZ]; | |
MoveAndWait(nextPos); | |
end; | |
end; | |
constructor TMicromanipulator.CreateManip(index: integer); | |
begin | |
fmanIndex := index; | |
name := 'Micromanipulator ' + IntToStr(index) + ': '; | |
end; | |
{*********************************** MP-285 ***********************************} | |
// | |
// Resolution of MP-285 is 5 microsteps /microns => 0.2 um / step by default | |
// | |
function TMP285.GetCoarseMotion: boolean; | |
begin | |
Result := (microstepsPerMicron = 5); | |
end; | |
procedure TMP285.SetCoarseMotion(value: boolean); | |
begin | |
if value then microstepsPerMicron := 5 else microstepsPerMicron := 25; | |
SetSpeed(fSpeed); | |
UpdateMP285Display; | |
end; | |
{procedure TMP285.GetResolution; | |
var MP285Config: TMP285Config; | |
begin | |
mmanOp := mmanGetResolution; | |
sserial := ''; | |
serialPort.PutString('s' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until mmanOp = mmanOK; | |
Move(sserial[1], MP285Config, SizeOf(MP285Config)); | |
if MP285Config.step_div > 32767 then high-order bit of step_div is set | |
microstepsPerMicron := 25 | |
else | |
microstepsPerMicron := 5; | |
end;} | |
procedure TMP285.Connect; | |
begin | |
inherited Connect; | |
try | |
with serialPort do | |
begin | |
Baud := COMSpeed; | |
COMNumber := COMPort; | |
Parity := pNone; | |
DataBits := 8; | |
StopBits := 1; | |
sSerial := ''; | |
serialPort.Open := True; | |
CRTriggerHandle := AddDataTrigger(Chr(13), False); | |
TimerHandle := AddTimerTrigger; | |
OnTriggerData := TriggerData; | |
OnTriggerAvail := TriggerAvail; | |
OnTriggerTimer := TimerReceived; | |
end; | |
mmanOp := mmanOK; | |
try | |
fBusy := False; | |
fDeviceState := dsDetected; | |
SetSpeed(fSpeed); | |
except | |
fDeviceState := dsNotFound; | |
end; | |
except | |
fDeviceState := dsNotFound; | |
end; | |
end; | |
procedure TMP285.TriggerData(CP: TObject; TriggerHandle: Word); | |
var newPos: array[0..2] of integer; | |
begin | |
serialPort.SetTimerTrigger(TimerHandle, 256, False); | |
if TriggerHandle <> CRTriggerHandle then Exit; | |
if mmanOp = mmanOK then Exit; {because TriggerData is called for the last CR} | |
case mmanOp of | |
mmanGetPos: | |
begin | |
if Length(sserial) >= SizeOf(newPos) then | |
begin | |
{copy return string} | |
Move(sserial[1], newPos, SizeOf(newPos)); | |
{convert microsteps into microns} | |
currentPos[mmanX] := newPos[0] / MICROSTEP_SIZE; | |
currentPos[mmanY] := newPos[1] / MICROSTEP_SIZE; | |
currentPos[mmanZ] := newPos[2] / MICROSTEP_SIZE; | |
end; | |
end; | |
end; | |
fBusy := False; | |
sSerial := ''; | |
mmanOp := mmanOK; | |
end; | |
procedure TMP285.UpdateMP285Display; | |
begin | |
fBusy := True; | |
mmanOp := mmanUpdateDisplay; | |
sserial := ''; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString('n' + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until mmanOp = mmanOK; | |
end; | |
procedure TMP285.TriggerAvail(CP: TObject; Count: Word); | |
var i: Word; | |
begin | |
for i := 1 to Count do | |
sserial := sserial + serialPort.GetChar; | |
end; | |
procedure TMP285.TimerReceived(CP: TObject; TriggerHandle: Word); | |
begin | |
if TriggerHandle = TimerHandle then | |
begin | |
{time-out: we lost the device} | |
fDeviceState := dsNotFound; | |
// serialPort.RemoveTrigger(TriggerHandle); | |
mmanOp := mmanOK; | |
end; | |
end; | |
procedure TMP285.GetXYZ; | |
begin | |
inherited GetXYZ; | |
if mmanOp <> mmanOK then Exit; | |
fBusy := True; | |
sserial := ''; | |
mmanOp := mmanGetPos; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
{06-23-06; Sutter MP-285 serial port leaves garbage; this cleans it} | |
PurgeComm(serialPort.Dispatcher.Handle, PURGE_RXCLEAR); | |
serialPort.PutString('c' + Chr(13)); | |
end; | |
procedure TMP285.MoveToXYZ(newX, newY, newZ: double); | |
var moverecord: TMP285MoveRec; | |
s: string; | |
begin | |
inherited MoveToXYZ(newX, newY, newZ); | |
if mmanOp <> mmanOK then Exit; | |
fBusy := True; | |
{converts microns to microsteps} | |
with moverecord do | |
begin | |
command := 'm'; | |
x := Round(newX * MICROSTEP_SIZE); {one microstep = 0.04 microns} | |
y := Round(newY * MICROSTEP_SIZE); | |
z := Round(newZ * MICROSTEP_SIZE); | |
end; | |
SetLength(s, SizeOf(TMP285MoveRec)); | |
Move(moverecord, s[1], SizeOf(TMP285MoveRec)); | |
sserial := ''; | |
mmanOp := mmanMove; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString(s + Chr(13)); {go for it} | |
end; | |
constructor TMP285.CreateManip(index: integer); | |
begin | |
inherited CreateManip(index); | |
name := 'MP-285 #' + IntToStr(index); | |
serialPort := TApdCOMPort.Create(nil); | |
serialPort.AutoOpen := False; | |
microstepsPerMicron := 5; {start with Coarse} | |
fSpeed := 1500; {1500 microns /s} | |
end; | |
procedure TMP285.SetSpeed(value: integer); | |
var s: string; | |
speedRecord : TMP285SpeedRec; | |
begin | |
inherited SetSpeed(value); | |
fBusy := True; | |
if mmanOp <> mmanOK then Exit; | |
if microstepsPerMicron = 5 then | |
begin {low resolution} | |
if (value <= 1) then value := 1; | |
if (value > 2900) then value := 2900; | |
end | |
else | |
begin | |
{1310 ~ 32767 / microstepsPerMicron} | |
if (value <= 1) then value := 1; | |
if (value > 1310) then value := 1310; | |
value := value Or 32768; {high bit set} | |
end; | |
speedRecord.command := 'v'; | |
speedRecord.speed := value; | |
SetLength(s, SizeOf(TMP285SpeedRec)); | |
Move(speedRecord, s[1], SizeOf(TMP285SpeedRec)); | |
mmanOp := mmanSetSpeed; | |
sserial := ''; | |
serialPort.SetTimerTrigger(TimerHandle, 256, True); | |
serialPort.PutString(s + Chr(13)); | |
repeat | |
Application.ProcessMessages; | |
until mmanOp = mmanOK; | |
end; | |
destructor TMP285.Destroy; | |
begin | |
serialPort.Free; | |
inherited Destroy; | |
end; | |
{****************************** LASER CONTROLS ********************************} | |
function TLaserControl.GetincA: double; | |
begin | |
Result := laserControlincA; | |
end; | |
function TLaserControl.GetincB: double; | |
begin | |
Result := laserControlincB; | |
end; | |
function TLaserControl.GetincC: double; | |
begin | |
Result := laserControlincC; | |
end; | |
function TLaserControl.GetincD: double; | |
begin | |
Result := laserControlincD; | |
end; | |
function TLaserControl.GetdecA: double; | |
begin | |
Result := laserControldecA; | |
end; | |
function TLaserControl.GetdecB: double; | |
begin | |
Result := laserControldecB; | |
end; | |
function TLaserControl.GetdecC: double; | |
begin | |
Result := laserControldecC; | |
end; | |
function TLaserControl.GetdecD: double; | |
begin | |
Result := laserControldecD; | |
end; | |
procedure TLaserControl.SetincA(value: double); | |
begin | |
laserControlincA := value; | |
end; | |
procedure TLaserControl.SetincB(value: double); | |
begin | |
laserControlincB := value; | |
end; | |
procedure TLaserControl.SetincC(value: double); | |
begin | |
laserControlincC := value; | |
end; | |
procedure TLaserControl.SetincD(value: double); | |
begin | |
laserControlincD := value; | |
end; | |
procedure TLaserControl.SetdecA(value: double); | |
begin | |
laserControldecA := value; | |
end; | |
procedure TLaserControl.SetdecB(value: double); | |
begin | |
laserControldecB := value; | |
end; | |
procedure TLaserControl.SetdecC(value: double); | |
begin | |
laserControldecC := value; | |
end; | |
procedure TLaserControl.SetdecD(value: double); | |
begin | |
laserControldecD := value; | |
end; | |
function TLaserControl.GetCOMPort: integer; | |
begin | |
Result := laserControlCOMPortIndex; | |
end; | |
function TLaserControl.GetCOMSpeed: integer; | |
begin | |
Result := laserControlCOMSpeedIndex; | |
end; | |
procedure TLaserControl.SetCOMPort(value: integer); | |
begin | |
laserControlCOMPortIndex := value; | |
end; | |
procedure TLaserControl.SetCOMSpeed(value: integer); | |
begin | |
laserControlCOMSpeedIndex := value; | |
end; | |
procedure TLaserControl.SetPower(newPower: double); | |
begin | |
if (newPower < 0) or (newPower > 100) then Exit; | |
fPower := newPower; | |
Mainform.OnNewPower; | |
end; | |
procedure TLaserControl.SetWavelength(newWavelength: integer); | |
begin | |
if (newWaveLength < 600) or (newWavelength > 1100) then Exit; | |
fWaveLength := newWavelength; | |
Mainform.OnNewWavelength; | |
end; | |
constructor TLaserControl.Create; | |
begin | |
fWavelength := 800; | |
fPower := 0; | |
name := 'No Laser Control'; | |
autoObject := TMPAutoLaserControl.Create as IMPLaserControl; | |
Connect; | |
end; | |
destructor TLaserControl.Destroy; | |
begin | |
autoObject := nil; | |
inherited Destroy; | |
end; | |
procedure TKimZhangLaserControl.SetPower( newPower : double); | |
var counter1, counter2: integer; | |
argcos: double; | |
begin | |
inherited SetPower(newPower); | |
{Assuming: power >= 0 and <= 100 | |
servo controlled by train pulse issued by GPCTR 0; timebase is 20 MHz = 50 ns | |
train pulse = 50 Hz = 20 ms = 400000; 1 ms = 20000 clock ticks @ 20 MHz} | |
if prevPower < newPower then | |
begin | |
argcos := (newPower/100 - incD)/incA; | |
if argcos < -1 then argcos := -1; | |
if argcos > 1 then argcos := 1; | |
counter1 := Round( 20000 * ( Arccos(argcos)- incC) / incB ); | |
end | |
else | |
begin | |
argcos := (newPower/100 - decD)/decA; | |
if argcos < -1 then argcos := -1; | |
if argcos > 1 then argcos := 1; | |
counter1 := Round( 20000 * ( Arccos(argcos) - decC) / decB ); | |
end; | |
prevPower := round (newPower); | |
if counter1 < 0 then counter1 := 0; | |
if counter1 > 400000 then counter1 := 400000; | |
counter2 := 400000 - counter1; {low period} | |
GPCTR_Control(multifunctionBoard.boardIndex, ND_COUNTER_1, ND_RESET); | |
GPCTR_Set_Application(multifunctionBoard.boardIndex, ND_COUNTER_1, ND_PULSE_TRAIN_GNR); | |
GPCTR_Change_Parameter(multifunctionBoard.boardIndex, ND_COUNTER_1, ND_GATE, ND_LOW); | |
GPCTR_Change_Parameter(multifunctionBoard.boardIndex, ND_COUNTER_1, ND_GATE_POLARITY, ND_HIGH_TO_LOW); | |
GPCTR_Change_Parameter(multifunctionBoard.boardIndex, ND_COUNTER_1, ND_SOURCE, ND_INTERNAL_20_MHZ); | |
GPCTR_Change_Parameter(multifunctionBoard.boardIndex, ND_COUNTER_1, ND_SOURCE_POLARITY, ND_LOW_TO_HIGH); | |
GPCTR_Change_Parameter(multifunctionBoard.boardIndex, ND_COUNTER_1, ND_COUNT_1, counter2); | |
GPCTR_Change_Parameter(multifunctionBoard.boardIndex, ND_COUNTER_1, ND_COUNT_2, counter1); | |
Select_Signal(multifunctionBoard.boardIndex, ND_GPCTR1_OUTPUT, ND_GPCTR1_OUTPUT, ND_LOW_TO_HIGH); | |
GPCTR_Control(multifunctionBoard.boardIndex, ND_COUNTER_1, ND_PROGRAM); | |
end; | |
procedure TKimZhangLaserControl.Connect; | |
begin | |
fDeviceState := dsDetected; | |
end; | |
constructor TKimZhangLaserControl.Create; | |
begin | |
inherited Create; | |
name := 'Kim and Zhang''s Laser Control'; | |
end; | |
{*********************************** Z Piezo **********************************} | |
procedure TZPiezo.OnScanningStarts; | |
begin | |
end; | |
procedure TZPiezo.OnScanningEnds; | |
begin | |
end; | |
function TZPiezo.ValidateParams(fromZ, toZ, deltaZ: double): boolean; | |
begin | |
Result := True; | |
end; | |
procedure TZPiezo.Connect; | |
begin | |
fDeviceState := dsNotInstalled; | |
end; | |
constructor TZPiezo.Create; | |
begin | |
inherited Create; | |
fZPiezoRange := 100; | |
name := 'Z- piezo'; | |
Connect; | |
end; | |
{********************************* MIPOS 100 **********************************} | |
{MIPOS 100 from PiezoJena: -100 microns displacement, 0..10V command maps to 0..100 microns} | |
procedure TMIPOS100.OnScanningStarts; {outputs a ramp} | |
var cPts, i: integer; | |
currentZ: double; | |
begin | |
if ((deviceStatus = dsInstalled) or (deviceStatus = dsDetected)) and Mainform.Configuration.PiezoEnableZMove then | |
with opticsOutputBoard, Mainform.Configuration do | |
if (PiezoIncrement <> 0) and (PiezoStartAtZ <> PiezoStopAtZ) then | |
begin | |
{find size of zPiezoValues array} | |
cPts := Abs(Round((PiezoStartAtZ - PiezoStopAtZ) / PiezoIncrement)) + 1; | |
{makes sure that cPts is a multiple of 2 (restriction of the PCI-6711)} | |
cPts := (cPts div 2) * 2; | |
SetLength(zPiezoValues, cPts); | |
{stuff values in zPiezoValues array} | |
currentZ := PiezoStartAtZ; | |
for i := 0 to cPts - 1 do | |
begin | |
{0.. -100 um => 0..10 V <=> 0..2047 digital values for a PCI-6711} | |
zPiezoValues[i] := Round(- currentZ * 2047 / fZPiezoRange); | |
currentZ := currentZ + PiezoIncrement; | |
end; | |
outputChannels[0] := zPiezoOutChannel; | |
WFM_Load(BoardIndex, 1 {one channel}, @outputChannels, pi16(@zPiezoValues[0]), | |
Length(zPiezoValues), REPEAT_INDEFINITELY, ENABLE_FIFO_MODE); | |
{Make sure that the analog output clock is on RTSI 0} | |
Select_Signal(BoardIndex, ND_OUT_UPDATE_CLOCK_TIMEBASE, ND_RTSI_0, ND_LOW_TO_HIGH); | |
{Start of data out is RTSI_1 - added 02/22/2008} | |
Select_Signal(BoardIndex, ND_OUT_START_TRIGGER, ND_RTSI_1, ND_LOW_TO_HIGH); | |
{find the clock; data out updated either every line scan or pixel} | |
if PiezoUpdateEveryLine then | |
WFM_ClockRate(BoardIndex, MPUnit.GROUP_1, UPDATE_CLOCK, EXT_TIMEBASE, | |
FullFrameWidth * PixelClock, MODE_0) | |
else | |
WFM_ClockRate(BoardIndex, MPUnit.GROUP_1, UPDATE_CLOCK, EXT_TIMEBASE, | |
FullFrameWidth * FrameHeight * PixelClock, MODE_0); | |
{starts waveform generation} | |
WFM_Group_Control(BoardIndex, 1, AO_START); | |
end; | |
end; | |
procedure TMIPOS100.OnScanningEnds; {at the end,put piezo back to original pos} | |
begin | |
if ((deviceStatus = dsInstalled) or (deviceStatus = dsDetected)) and Mainform.Configuration.PiezoEnableZMove then | |
with opticsOutputBoard, Mainform.Configuration do | |
begin | |
{stop analog output} | |
WFM_Group_Control(BoardIndex, 1, AO_CLEAR); | |
{piezo at original position} | |
AO_Write(BoardIndex, zPiezoOutChannel, Round(- PiezoStartAtZ * 2047 / fZPiezoRange)); | |
end; | |
end; | |
function TMIPOS100.ValidateParams(fromZ, toZ, deltaZ: double): boolean; | |
begin | |
Result := True; | |
if (fromZ < -ZPiezoRange) or (fromZ > 0) or (toZ < -ZPiezoRange) or (toZ > 0) or (Abs(fromZ - toZ) > fZPiezoRange) or | |
(Abs(deltaZ) > fZPiezoRange) or (fromZ - toZ = 0) or (deltaZ = 0) then Result := False | |
else if Abs(Round((fromZ - toZ) / deltaZ) + 1) > opticsOutputBoard.FIFOSampleCount then | |
Result := False | |
else if ((fromZ <= toZ) and (deltaZ <= 0)) or ((fromZ >= deltaZ) and (deltaZ >= 0)) then | |
Result := False; | |
end; | |
procedure TMIPOS100.Connect; | |
begin | |
fDeviceState := opticsOutputBoard.deviceStatus; | |
end; | |
{********************************* PIFOC 725 **********************************} | |
constructor TMIPOS100.Create; | |
begin | |
inherited Create; | |
fZPiezoRange := 100; | |
name := '100 um range Z- piezo'; | |
end; | |
{********************************* PIFOC 725 **********************************} | |
constructor TPIFOC725.Create; | |
begin | |
inherited Create; | |
fZPiezoRange := 400; | |
name := '400 um range Z- piezo'; | |
end; | |
{******************************************************************************} | |
{* XPS controller *} | |
{******************************************************************************} | |
{********************************* TZ_XYZ *************************************} | |
function TZ_XPS.GetDeviceState: TDeviceState; | |
begin | |
Result := xps.DeviceStatus; | |
end; | |
procedure TZ_XPS.SetSpeed(speedIndex: integer); | |
begin | |
inherited SetSpeed(speedIndex); | |
if (speedIndex < 1) or (speedIndex > 20) then Exit; | |
xps.SetZSpeed(speedIndex); | |
end; | |
procedure TZ_XPS.Connect; | |
begin | |
end; | |
{asynchronous: GetZ, MoveToRelative, SetZ} | |
procedure TZ_XPS.GetZ(var newZ: double); | |
begin | |
xps.GetZ(newZ); | |
end; | |
procedure TZ_XPS.MoveToRelativeZ(newDeltaZ: double); | |
begin | |
inherited MoveToRelativeZ(newDeltaZ); | |
if InvertZ then newDeltaZ := - newDeltaZ; | |
xps.ShiftByZ(newDeltaZ); | |
end; | |
procedure TZ_XPS.SetZ(var newZ: double); | |
begin | |
inherited SetZ(newZ); | |
xps.SetZ(newZ); | |
end; | |
{synchronous calls: MoveToZ, ReadZ, ShiftByZ} | |
procedure TZ_XPS.MoveToZ(newZ: double); | |
begin | |
inherited MoveToZ(newZ); | |
xps.MoveToZ(newZ); | |
repeat | |
Application.ProcessMessages; | |
until not Busy; | |
end; | |
function TZ_XPS.ReadZ: double; | |
begin | |
Result := xps.ReadZ; | |
end; | |
procedure TZ_XPS.ShiftByZ(deltaZ: double); | |
begin | |
inherited ShiftByZ(deltaZ); | |
if InvertZ then deltaZ := - deltaZ; | |
xps.ShiftByZ(deltaZ); | |
repeat | |
Application.ProcessMessages; | |
until not Busy; | |
end; | |
function TZ_XPS.TravelTime(zTravel: integer; speedIndex: integer): double; | |
begin | |
if DeviceStatus = dsDetected then | |
Result := zTravel / XPSZSpeed(speedIndex) | |
else | |
Result := 0; | |
end; | |
procedure TZ_XPS.StartFastScan; | |
begin | |
inherited StartFastScan; | |
startFastScanPosition := ZPosition; | |
curFastRepeatCount := 0; | |
with Mainform.configuration do | |
if zDistance > 0 then | |
xps.StartFastStack(Mainform.Configuration.TravelSpeed, stepSize) | |
else | |
xps.StartFastStack(Mainform.Configuration.TravelSpeed, -stepSize); | |
end; | |
procedure TZ_XPS.StopFastScan; | |
begin | |
inherited StopFastScan; | |
{return to old speed} | |
xps.SetZSpeed(Speed); | |
end; | |
constructor TZ_XPS.Create; | |
begin | |
inherited Create; | |
name := 'Z- XPS controller'; | |
fStepSize := 0.1; {assume 0.1 micron for the minimal step size} | |
end; | |
destructor TZ_XPS.Destroy; | |
begin | |
inherited Destroy; | |
end; | |
{********************************* TXY_XPS ************************************} | |
function TXY_XPS.GetDeviceState: TDeviceState; | |
begin | |
Result := xps.deviceStatus; | |
end; | |
procedure TXY_XPS.SetSpeed(value: integer); | |
begin | |
xps.SetXYSpeed(value); | |
end; | |
procedure TXY_XPS.Connect; | |
begin | |
xps.Connect; | |
end; | |
{asynchronous} | |
procedure TXY_XPS.GetXY(var newX, newY: integer); | |
begin | |
xps.GetXY(newX, newY); | |
end; | |
procedure TXY_XPS.SetXY(var newX, newY: integer); | |
begin | |
inherited SetXY(newX, newY); | |
xps.SetXY(newX, newY); | |
end; | |
procedure TXY_XPS.SetRelativeXY(deltaX, deltaY: integer); | |
begin | |
inherited SetRelativeXY(deltaX, deltaY); | |
if XYTable.InvertX then deltaX := -deltaX; | |
if XYTable.InvertY then deltaY := -deltaY; | |
xps.SetRelativeXY(deltaX, deltaY); | |
end; | |
{synchronous} | |
procedure TXY_XPS.MoveToXY(newX, newY: integer); | |
begin | |
inherited MoveToXY(newX, newY); | |
xps.MoveToXY(newX, newY); | |
repeat | |
Application.ProcessMessages; | |
until not XYTable.Busy; | |
end; | |
procedure TXY_XPS.ReadXY(var x, y: integer); | |
begin | |
xps.ReadXY(x, y); | |
end; | |
procedure TXY_XPS.ShiftByXY(deltaX, deltaY: integer); | |
begin | |
inherited ShiftByXY(deltaX, deltaY); | |
if XYTable.InvertX then deltaX := -deltaX; | |
if XYTable.InvertY then deltaY := -deltaY; | |
xps.ShiftByXY(deltaX, deltaY); | |
repeat | |
Application.ProcessMessages; | |
until not XYTable.Busy; | |
end; | |
procedure TXY_XPS.XYCommand(const sCommand: string); | |
begin | |
xps.XYCommand(sCommand); | |
end; | |
constructor TXY_XPS.Create; | |
begin | |
inherited Create; | |
name := 'XY- XPS controller'; | |
xps := TXPS.Create; | |
end; | |
destructor TXY_XPS.Destroy; | |
begin | |
xps.Free; | |
inherited Destroy; | |
end; | |
{********************************* TXPS ************************************} | |
{Assume units are in mm} | |
procedure TXPS.SetXYSpeed(speedIndex: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
if not (xyTable.Busy or zStepper.Busy) then | |
begin | |
xpsAction := xpsa_SET_XY_SPEED; | |
xpsParam1 := speedIndex; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
end; | |
end; | |
procedure TXPS.SetZSpeed(speedIndex: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
if not (xyTable.Busy or zStepper.Busy) then | |
begin | |
xpsAction := xpsa_SET_Z_SPEED; | |
xpsParam1 := speedIndex; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
end; | |
end; | |
procedure TXPS.Connect; | |
begin | |
if not LoadXPSLibrary then | |
fDeviceState := dsNotFound | |
else | |
try | |
if ConnectToXPS then | |
fDeviceState := dsDetected | |
else | |
fDeviceState := dsNotFound; | |
except | |
fDeviceState := dsNotFound; | |
end; | |
end; | |
procedure TXPS.GetZ(var newZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
xpsAction := xpsa_GET_Z; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
newZ := zStepper.ZPosition; | |
end; | |
procedure TXPS.MoveToRelativeZ(newDeltaZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
if not (xyTable.Busy or zStepper.Busy) then | |
begin | |
xpsAction := xpsa_SET_TO_RELATIVE_Z; | |
xpsParam1 := newDeltaZ; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
end; | |
end; | |
procedure TXPS.SetZ(var newZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
if not (xyTable.Busy or zStepper.Busy) then | |
begin | |
xpsAction := xpsa_SET_Z; | |
xpsParam1 := newZ; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
end; | |
end; | |
procedure TXPS.MoveToZ(newZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
SetZ(newZ); | |
end; | |
function TXPS.ReadZ: double; | |
begin | |
if ZStepper.deviceStatus <> dsDetected then | |
Result := 0 | |
else | |
begin | |
xpsAction := xpsa_READ_Z; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
Result := zStepper.ZPosition; | |
end; | |
end; | |
procedure TXPS.ShiftByZ(deltaZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
MoveToRelativeZ(deltaZ); | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
end; | |
procedure TXPS.GetXY(var newX, newY: integer); | |
begin | |
newX := 0; newY := 0; | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
xpsAction := xpsa_GET_XY; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
newX := XYTable.XPosition; | |
newY := XYTable.YPosition; | |
end; | |
procedure TXPS.SetXY(var newX, newY: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
if not (xyTable.Busy or zStepper.Busy) then | |
begin | |
xpsAction := xpsa_SET_XY; | |
xpsParam1 := newX; | |
xpsParam2 := newY; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
end; | |
end; | |
procedure TXPS.SetRelativeXY(deltaX, deltaY: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
if not (xyTable.Busy or zStepper.Busy) then | |
begin | |
xpsAction := xpsa_SET_TO_RELATIVE_XY; | |
xpsParam1 := deltaX; | |
xpsParam2 := deltaY; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
end; | |
end; | |
procedure TXPS.FastStackCallback; | |
var bFinished: boolean; | |
newPower: integer; | |
currentDisplacement: double; | |
begin | |
bFinished := False; | |
with ZStepper do | |
if not Odd(curFastRepeatCount) and (Mainform.Configuration.zDistance < 0) then | |
fastStackInterval {in microns}:= - ZStepper.StepSize / 1000 | |
else | |
fastStackInterval {in microns}:= ZStepper.StepSize / 1000; | |
{Adjust laser power here} | |
with Mainform.Configuration, Mainform.engine do | |
if IntensityControl <> IC_NO_CONTROL then | |
begin | |
currentDisplacement := - zStepper.startFastScanPosition + zStepper.fZPosition; | |
if IntensityControl = IC_LINEAR then | |
newPower := Round(currentDisplacement * (FinalIntensity - InitialIntensity)/AtZDistance + InitialIntensity) | |
// analogOutputBoard.AnalogOut(1, TrackBar3.Position/10); | |
else | |
begin | |
if InitialIntensity <= 0 then InitialIntensity := 1; | |
newPower := Round(InitialIntensity *exp(currentDisplacement * Ln(FinalIntensity/InitialIntensity) / AtZDistance)); | |
end; | |
if Abs(newPower - LaserControl.Power) > 0 then | |
begin | |
analogOutputBoard.AnalogOut(1, newPower/10); | |
LaserControl.Power := newPower; | |
end; | |
end; | |
// analogOutputBoard.AnalogOut(1, LaserControl.Power/10); | |
with ZStepper do | |
if (ZPosition = startFastScanPosition + Mainform.Configuration.zDistance) or | |
(ZPosition = startFastScanPosition) then | |
begin | |
curFastRepeatCount := curFastRepeatCount + 1; | |
if curFastRepeatCount >= Mainform.Configuration.FastStackRepeatCount then | |
begin | |
bFinished := True; | |
PostMessage(Mainform.Handle, WM_FASTSTACK_ENDED, 0, 0); | |
end; | |
end; | |
if not bFinished then ReleaseSemaphore(xpsSemaphore, 1, nil); | |
end; | |
procedure TXPS.MoveToXY(newX, newY: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
if not (xyTable.Busy or zStepper.Busy) then | |
begin | |
xpsAction := xpsa_MOVE_TO_XY; | |
xpsParam1 := newX; | |
xpsParam2 := newY; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
end; | |
end; | |
procedure TXPS.ReadXY(var x, y: integer); | |
begin | |
x := 0; y := 0; | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
GetXY(x, y); | |
end; | |
procedure TXPS.ShiftByXY(deltaX, deltaY: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
if not (xyTable.Busy or zStepper.Busy) then | |
begin | |
xpsAction := xpsa_SHIFT_BY_XY; | |
xpsParam1 := deltaX; | |
xpsParam2 := deltaY; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
end; | |
end; | |
procedure TXPS.XYCommand(const sCommand: string); | |
begin | |
end; | |
procedure TXPS.StartFastStack(fsSpeed: integer; deltaZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
SetZSpeed(fsSpeed); | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
xpsAction := xpsa_FAST_STACK; | |
fastStackInterval {in microns}:= deltaZ / 1000; | |
ReleaseSemaphore(xpsSemaphore, 1, nil); {starts the thread} | |
end; | |
constructor TXPS.Create; | |
begin | |
inherited Create; | |
{load the pointers to the functions with LoadLibrary} | |
xpsAction := xpsa_NO_ACTION; | |
xpsSemaphore := CreateSemaphore(nil, 0, 1, nil); | |
xpsThread := TXPSThread.Create(False); | |
end; | |
destructor TXPS.Destroy; | |
begin | |
xpsThread.Terminate; | |
CloseHandle(xpsSemaphore); | |
UnloadXPSLibrary; | |
inherited Destroy; | |
end; | |
{******************************************************************************} | |
{* Galil DMC-40 controller *} | |
{******************************************************************************} | |
{********************************* TZ_XYZ *************************************} | |
function TZ_DMC40.GetDeviceState: TDeviceState; | |
begin | |
Result := dmc40.DeviceStatus; | |
end; | |
procedure TZ_DMC40.Connect; | |
begin | |
end; | |
procedure TZ_DMC40.GetZ(var newZ: double); | |
begin | |
dmc40.GetZ(newZ); | |
end; | |
procedure TZ_DMC40.MoveToRelativeZ(newDeltaZ: double); | |
begin | |
//jdp - called when user clicks on move button | |
inherited MoveToRelativeZ(newDeltaZ); | |
if InvertZ then newDeltaZ := - newDeltaZ; | |
dmc40.ShiftByZ(newDeltaZ); | |
end; | |
procedure TZ_DMC40.SetZ(var newZ: double); | |
begin | |
inherited SetZ(newZ); | |
dmc40.SetZ(newZ); | |
end; | |
procedure TZ_DMC40.MoveToZ(newZ: double); | |
begin | |
inherited MoveToZ(newZ); | |
dmc40.MoveToZ(newZ); | |
repeat | |
Application.ProcessMessages; | |
until not Busy; | |
end; | |
function TZ_DMC40.ReadZ: double; | |
begin | |
Result := dmc40.ReadZ; | |
end; | |
procedure TZ_DMC40.ShiftByZ(deltaZ: double); | |
begin | |
inherited ShiftByZ(deltaZ); | |
if InvertZ then deltaZ := - deltaZ; | |
dmc40.ShiftByZ(deltaZ); | |
repeat | |
Application.ProcessMessages; | |
until not Busy; | |
end; | |
function TZ_DMC40.TravelTime(zTravel: integer; speedIndex: integer): double; | |
//Mainform.Configuration.TravelSpeed and speedIndex both read the value of the slider (1 to 60) // PB | |
begin | |
if DeviceStatus = dsDetected then | |
Result := round(zTravel / Mainform.Configuration.TravelSpeed * 1000)/1000 // PB | |
else | |
Result := 0; | |
end; | |
procedure TZ_DMC40.StartFastScan; | |
begin | |
inherited StartFastScan; | |
startFastScanPosition := ZPosition; | |
curFastRepeatCount := 0; | |
//messageBox(0,PAnsiChar(FloatToStr(stepSize)),'TZ_DMC40.StartFastScan',0); //PB | |
with Mainform.configuration do | |
if zDistance > 0 then | |
dmc40.StartFastStack(Mainform.Configuration.TravelSpeed, stepSize) | |
else | |
dmc40.StartFastStack(Mainform.Configuration.TravelSpeed, -stepSize); | |
end; | |
procedure TZ_DMC40.StopFastScan; | |
begin | |
inherited StopFastScan; | |
{return to old speed} | |
// dmc40.SetZSpeed(Speed); | |
end; | |
constructor TZ_DMC40.Create; | |
begin | |
inherited Create; | |
name := 'Z- Galil DMC-40 controller'; | |
fStepSize := 5/16; {assume 0.3125 micron for the minimal step size} //STEP NEED TO CHANGE | |
end; | |
destructor TZ_DMC40.Destroy; | |
begin | |
inherited Destroy; | |
end; | |
{********************************* TXY_DMC40 ************************************} | |
function TXY_DMC40.GetDeviceState: TDeviceState; | |
begin | |
Result := dmc40.deviceStatus; | |
end; | |
procedure TXY_DMC40.Connect; | |
begin | |
dmc40.Connect; | |
end; | |
{asynchronous} | |
procedure TXY_DMC40.GetXY(var newX, newY: integer); | |
begin | |
dmc40.GetXY(newX, newY); | |
end; | |
procedure TXY_DMC40.SetXY(var newX, newY: integer); | |
begin | |
inherited SetXY(newX, newY); | |
dmc40.SetXY(newX, newY); | |
end; | |
procedure TXY_DMC40.SetRelativeXY(deltaX, deltaY: integer); | |
begin | |
//jdp - called when user moves stage (by move buttons) | |
inherited SetRelativeXY(deltaX, deltaY); | |
if XYTable.InvertX then deltaX := -deltaX; | |
if XYTable.InvertY then deltaY := -deltaY; | |
dmc40.SetRelativeXY(deltaX, deltaY); | |
end; | |
{synchronous} | |
procedure TXY_DMC40.MoveToXY(newX, newY: integer); | |
begin | |
inherited MoveToXY(newX, newY); | |
dmc40.MoveToXY(newX, newY); | |
repeat | |
Application.ProcessMessages; | |
until not XYTable.Busy; | |
end; | |
procedure TXY_DMC40.ReadXY(var x, y: integer); | |
begin | |
dmc40.ReadXY(x, y); | |
//jdp | |
//MessageBox(0,pchar(intToStr(x) + ' ' + | |
// intToStr(y) + ' '), | |
// 'TXY_DMC40.ReadXY',0); | |
end; | |
procedure TXY_DMC40.ShiftByXY(deltaX, deltaY: integer); | |
begin | |
inherited ShiftByXY(deltaX, deltaY); | |
if XYTable.InvertX then deltaX := -deltaX; | |
if XYTable.InvertY then deltaY := -deltaY; | |
dmc40.ShiftByXY(deltaX, deltaY); | |
repeat | |
Application.ProcessMessages; | |
until not XYTable.Busy; | |
end; | |
procedure TXY_DMC40.XYCommand(const sCommand: string); | |
begin | |
dmc40.XYCommand(sCommand); | |
end; | |
//PB | |
procedure TXY_DMC40.GalilWaitForMotionComplete; | |
begin | |
dmc40.GalilWaitForMotionComplete; | |
end; | |
constructor TXY_DMC40.Create; | |
begin | |
inherited Create; | |
name := 'XY- Galil DMC-40 controller'; | |
dmc40 := TDMC40.Create; | |
end; | |
destructor TXY_DMC40.Destroy; | |
begin | |
dmc40.Free; | |
inherited Destroy; | |
end; | |
{********************************* TDMC40 ************************************} | |
{hidden object controlling the Galil controller} | |
procedure TDMC40.Connect; | |
begin | |
if GalilThread.Connected then | |
fDeviceState := dsDetected | |
else | |
fDeviceState := dsNotFound; | |
end; | |
procedure TDMC40.GetZ(var newZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
GalilThread.GalilAction := GALIL_GET_Z; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
newZ := zStepper.ZPosition; | |
end; | |
procedure TDMC40.MoveToRelativeZ(newDeltaZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
if (mainform.configuration.ScanMode = SM_STACK) and mainform.scanning then | |
GalilThread.GalilAction:= GALIL_SET_TO_RELATIVE_Z_NO_UPDATE | |
else | |
GalilThread.GalilAction:= GALIL_SET_TO_RELATIVE_Z; | |
GalilThread.GalilParam1 := newDeltaZ; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
end; | |
//jdz | |
procedure TDMC40.SetZ(var newZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
ZStepper.Busy := True; | |
GalilThread.GalilAction:= GALIL_SET_Z; | |
GalilThread.GalilParam1 := newZ; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
end; | |
procedure TDMC40.MoveToZ(newZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
SetZ(newZ); | |
end; | |
function TDMC40.ReadZ: double; | |
begin | |
if ZStepper.deviceStatus <> dsDetected then | |
Result := 0 | |
else | |
begin | |
GalilThread.GalilAction := GALIL_READ_Z; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
Result := zStepper.ZPosition; | |
end; | |
end; | |
procedure TDMC40.ShiftByZ(deltaZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
MoveToRelativeZ(deltaZ); | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
end; | |
procedure TDMC40.GetXY(var newX, newY: integer); | |
begin | |
newX := 0; newY := 0; | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
GalilThread.GalilAction := GALIL_GET_XY; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
newX := XYTable.XPosition; | |
newY := XYTable.YPosition; | |
end; | |
procedure TDMC40.SetXY(var newX, newY: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
GalilThread.GalilAction := GALIL_SET_XY; | |
GalilThread.GalilParam1 := newX; | |
GalilThread.GalilParam2 := newY; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
end; | |
procedure TDMC40.SetRelativeXY(deltaX, deltaY: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
GalilThread.GalilAction := GALIL_SET_TO_RELATIVE_XY; | |
GalilThread.GalilParam1 := deltaX; | |
GalilThread.GalilParam2 := deltaY; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
end; | |
//jd - note this function has changed to do a "one shot" | |
// fast stack, using continuous motion | |
// to see how it was previously coded (multiple callbacks), | |
// check FastStackCallback for other stages | |
// this will only do one fast stack (down and up) | |
procedure TDMC40.FastStackCallback; | |
var newPower: integer; | |
currentDisplacement: double; | |
inMo: boolean; //jdz | |
zPosUm: double; //jdz - last Z position, in microns | |
zPosInitialUm: double; | |
zPosFinalUm: double; | |
temp: double; | |
begin | |
//messageBox(0,PAnsiChar(FloatToStr(fastStackInterval)),'In TDMC40.FastStackCallback',0); //PB | |
// setup; | |
inMo := true; | |
GalilThread.GetZ( zPosUm ); | |
zPosInitialUm := zPosUm; | |
zPosFinalUm := zPosUm + GalilThread.fastStackDistance; // generally, fastStackDistance will be negative | |
// set to initial power here | |
LaserControl.Power := Round(Mainform.Configuration.InitialIntensity); | |
while inMo do | |
begin | |
//if inMo then messageBox(0,'true (moving)','',0) | |
//else messageBox(0,'false (not moving)','',0); | |
Delay(50); // don't check stage constantly | |
inMo := GalilThread.InMotionZ; // check the motion | |
GalilThread.GetZ( zPosUm ); // get current position | |
// messageBox(0,pansiChar(floatToStr(zPosUm)),'',0); | |
// stop motion if no longer scanning (if user exits) | |
if mainform.scanning = false then | |
begin | |
inMo := false; | |
GalilThread.StopMotion; | |
end; | |
{Adjust laser power here, if enabled} | |
with Mainform.Configuration, Mainform.engine do | |
if IntensityControl <> IC_NO_CONTROL then | |
begin | |
currentDisplacement := zPosUm - zPosInitialUm; | |
if IntensityControl = IC_LINEAR then | |
begin | |
newPower := Round(InitialIntensity + | |
currentDisplacement/AtZDistance * (FinalIntensity - InitialIntensity)); | |
end | |
else | |
begin | |
if InitialIntensity <= 0 then InitialIntensity := 1; // don't divide by 0 | |
newPower := Round(InitialIntensity * | |
exp(currentDisplacement * Ln(FinalIntensity/InitialIntensity) / AtZDistance)); | |
end; | |
if Abs(newPower - LaserControl.Power) <> 0 then | |
begin | |
analogOutputBoard.AnalogOut(1, newPower/10); | |
LaserControl.Power := newPower; | |
end; | |
end; | |
end; // in inMo loop | |
// done with fast stack | |
// (either stage stopped moving, or user pressed stop | |
GalilThread.ResetSpeedAndPosAfterFastStackZ; // return to original speed | |
// return to original power | |
LaserControl.Power := Round(Mainform.Configuration.InitialIntensity); | |
//jdz - this will call WMFASTSTACKENDED and stop the scan, and return stage | |
PostMessage(Mainform.Handle, WM_FASTSTACK_ENDED, 0, 0); | |
end; | |
procedure TDMC40.MoveToXY(newX, newY: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
XYTable.Busy := True; | |
GalilThread.GalilAction := GALIL_MOVE_TO_XY; | |
GalilThread.GalilParam1 := newX; | |
GalilThread.GalilParam2 := newY; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
end; | |
procedure TDMC40.ReadXY(var x, y: integer); | |
begin | |
x := 0; y := 0; | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
GetXY(x, y); | |
end; | |
procedure TDMC40.ShiftByXY(deltaX, deltaY: integer); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
GalilThread.GalilAction := GALIL_SHIFT_BY_XY; | |
GalilThread.GalilParam1 := deltaX; | |
GalilThread.GalilParam2 := deltaY; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
end; | |
procedure TDMC40.XYCommand(const sCommand: string); | |
begin | |
GalilThread.GalilAction := GALIL_COMMAND; | |
GalilThread.GalilCommandString := sCommand; | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
end; | |
//PB | |
procedure TDMC40.GalilWaitForMotionComplete; | |
begin | |
//add stuff | |
end; | |
procedure TDMC40.StartFastStack(fsSpeed: integer; deltaZ: double); | |
begin | |
if ZStepper.deviceStatus <> dsDetected then Exit; | |
// SetZSpeed(fsSpeed); | |
repeat | |
Application.ProcessMessages; | |
until not ZStepper.Busy; | |
GalilThread.GalilAction := GALIL_FAST_STACK; | |
//jdz - pass in parameters needed by the fast stack | |
GalilThread.fastStackInterval := deltaZ; // (microns) not currently used | |
GalilThread.fastStackSpeed := fsSpeed; // number between 1-60 (microns per sec) | |
GalilThread.fastStackDistance := Mainform.configuration.zDistance; // microns | |
ReleaseSemaphore(GalilSemaphore, 1, nil); {starts the thread} | |
end; | |
constructor TDMC40.Create; | |
begin | |
inherited Create; | |
GalilSemaphore := CreateSemaphore(nil, 0, 1, nil); | |
GalilThread := TGalilThread.Create(True); | |
GalilThread.ConnectToGalil; | |
GalilThread.Resume; | |
end; | |
destructor TDMC40.Destroy; | |
begin | |
GalilThread.Terminate; | |
Delay(1000); //jd wait for thread to terminate | |
CloseHandle(GalilSemaphore); | |
inherited Destroy; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit mpfileu; | |
interface | |
uses Windows, Messages, SysUtils, Classes, Graphics, Forms, Registry, StdCtrls, ActiveX, | |
ComObj, mpviewu, vfw; | |
type | |
TMPFile = class; | |
TFrame = class | |
private | |
chIndex, frameIndex: integer; | |
mpFile: TMPFile; | |
procedure LoadFromFile(frameIndex: integer); virtual; abstract; | |
public | |
data: array of int16; | |
constructor Create(mp_File: TMPFile; iChIndex, iFrameIndex: integer); | |
end; | |
TVideoFrame = class(TFrame) | |
private | |
function GetHeight: integer; | |
function GetPixels(x, y: integer): int16; | |
function GetWidth: integer; | |
procedure LoadFromFile(frameIndex: integer); override; | |
procedure SaveToFile; | |
public | |
procedure CopyData(dest: TVideoFrame); | |
procedure CopyToDoubleArray(var dblArray: array of double); | |
procedure GammaCorrection(blackLevel, whiteLevel: integer); | |
procedure GetProfile(binSize: integer; var histogram: array of integer); | |
constructor Create(mp_File: TMPFile; iChIndex, iFrameIndex: integer); | |
property Height: integer read GetHeight; | |
property Pixels[x, y: integer]: int16 read GetPixels; | |
property Width: integer read GetWidth; | |
end; | |
TAnalogFrame = class(TFrame) | |
{x: index of analog sample in frame data} | |
private | |
function GetIAnalogValue(x: integer): integer; | |
function GetfAnalogValue(x: integer): double; | |
procedure LoadFromFile(frameIndex: integer); override; | |
public | |
function SampleToAbsoluteTime(x: integer): double; {in seconds} | |
constructor Create(mp_File: TMPFile; iChIndex, iFrameIndex: integer); | |
property iAnalogValue[x: integer]: integer read GetIAnalogValue; | |
property fAnalogValue[x: integer]: double read GetfAnalogValue; | |
end; | |
TFrameCommentList = class(TStringList) | |
private | |
mpFile: TMPFile; | |
procedure SaveFrameComments; | |
procedure LoadFrameComments; | |
function GetFrameComment(frameIndex: integer): string; | |
procedure SetFrameComment(frameIndex: integer; const frameComment: string); | |
public | |
constructor Create(theMPFile: TMPFile); | |
property FrameComment[frameIndex: integer]: string read GetFrameComment write SetFrameComment; | |
end; | |
TFrameGroup = class | |
private | |
fWidth, fHeight, fFrameIndex: integer; | |
mpFile: TMPFile; | |
procedure LoadFromFile(frameIndex: integer); | |
{ procedure SaveToFile;} | |
procedure SetFrameWidth(newWidth: integer); | |
procedure SetFrameHeight(newHeight: integer); | |
procedure SetFrameIndex(newIndex: integer); | |
public | |
comments: string; | |
channels: array[0..MAX_CH - 1] of TFrame; {0..1: TVideoFrame; 2..3: TAnalogFrame} | |
property FrameIndex: integer read fFrameIndex write SetFrameIndex; | |
property FrameWidth: integer read fWidth write SetFrameWidth; | |
property FrameHeight: integer read fHeight write SetFrameHeight; | |
constructor Create(mp_file: TMPFile); | |
constructor CreateTempFrameGroup(mp_file: TMPFile); | |
constructor CreateForOp(mp_file: TMPFile); {creates a frame group for operations: only channels[0] is valid} | |
destructor Destroy; override; | |
end; | |
//-------------------------------- FILE OBJECT ------------------------------ | |
TIntensityControl = (IC_NO_CONTROL, IC_LINEAR, IC_EXPONENTIAL); | |
TMPFile = class | |
private | |
fActiveFrameIndex: integer; | |
fAngle: integer; | |
{fbLineForXScan, OBSOLETE} | |
fbIsMemoryFile, fbClosing: boolean; | |
fChConvFactors: array[0..MAX_CH -1] of double; | |
fChDataPtsPerFrames: array[0..MAX_CH -1] of integer; | |
fChEnabled, fIsVideoCh: array[0..MAX_CH - 1] of boolean; | |
fChInputRanges: array[0..MAX_CH - 1] of TFullScaleVal; | |
fChNames: array[0..MAX_CH - 1] of string; | |
fChMaxPixelValues: array[0..MAX_CH - 1] of integer; | |
fChOffsets: array[0..MAX_CH -1] of double; | |
fChPrefixes: array[0..MAX_CH -1] of TPrefix; | |
fChUnits: array[0..MAX_CH - 1] of string; | |
fFilename: string; | |
fFrameCount: integer; | |
fFrameHeight, | |
fFrameWidth: integer; | |
fLineRepeatCount: integer; | |
fMagnification: double; | |
fPixelClock {in increments of 50 ns (= 20 MHz)}: integer; | |
fResolution: TFrameResolution; {RESOLUTION_8_BITS, 12, 16 bits} | |
fRotation: integer; | |
fScanMode: TScanMode; | |
fStackAveragingCount, | |
fStackFrameCount: integer; | |
fStackInterval: double; | |
fStackRepeatCount, | |
fXFrameOffset, | |
fXStagePosition, | |
fYFrameOffset, | |
fYStagePosition: integer; | |
fZStagePosition: double; | |
sComments: string; | |
fzDistance: double; | |
fTravelDuration: string; | |
fFastStackRepeatCount: integer; | |
fInitialIntensity, fFinalIntensity: integer; | |
fAtZDistance: double; | |
fIntensityControl: TIntensityControl; | |
RegionPts: array of TPoint; {for region scans} | |
chStreams: array[0..MAX_CH -1] of IStream; | |
propertyStorage: IPropertyStorage; | |
propertySetStorage: IPropertySetStorage; | |
rootStorage: IStorage; | |
fCurrentFrameGroup: TFrameGroup; | |
frameCommentList: TFrameCommentList; | |
frameGroupList: TList; | |
bDirty: boolean; | |
{ function GetActiveFrameGroup: TFrameGroup;} | |
procedure AdjustFrameCount; | |
function GetAnalogChCount: integer; | |
function GetAnalogChEnabled(chIndex: integer): boolean; | |
function GetAnalogWndCount: integer; | |
function GetAnalogWnds(wndIndex: integer): TForm; | |
function GetChAcquisitionRate(chIndex: integer): double; | |
function GetChConvFactor(chIndex: integer): double; | |
function GetChDataPtsPerFrame(chIndex: integer): integer; | |
function GetChEnabled(chIndex: integer): boolean; | |
function GetChInputRange(chIndex: integer): TFullScaleVal; | |
function GetChMaxPixelValues(chIndex: integer): integer; | |
function GetChNames(chIndex: integer): string; | |
function GetChUnit(chIndex: integer): string; | |
function GetChPrefix(chIndex: integer): TPrefix; | |
function GetChOffset(chIndex: integer): double; | |
{ function GetCurrentFrame(chIndex: integer): TFrame;} | |
function GetDefaultVideoChannel: integer; | |
function GetFrameComment(frameIndex: integer): string; | |
function GetFrameCount: integer; | |
function GetFrameRate: double; {in frames per seconds} | |
function GetFrameSize: integer; | |
function GetFrames(frameIndex: integer): TFrameGroup; | |
function GetFullFrameSize: integer; | |
function GetIsVideoChannel(chIndex: integer): boolean; | |
function GetMaxPixelValue: integer; | |
procedure GetRegions; | |
function GetResolution: string; | |
function GetVideoChCount: integer; | |
function GetVideoChEnabled(chIndex: integer): boolean; | |
function GetViewerCount: integer; | |
function GetViewers(viewerIndex: integer): TForm; | |
procedure InitializeColors; | |
procedure LoadFrameGroup(newIndex: integer); | |
procedure ReadPropertySet; | |
procedure SetActiveFrameIndex(newIndex: integer); | |
procedure SetFrameComment(frameIndex: integer; sComments: string); | |
procedure WritePropertySet; | |
public | |
viewerList, analogWndList: TList; | |
{custom LUTs} | |
baseColors: TBaseColorsArray; | |
negativeColors, | |
midRangeColors, | |
maxColors: TRangeColorsArray; | |
maxPixels: TMaxPixelsArray; | |
CustomColors: array[0..MAX_CH - 1, 0..MAX_FALSE_COLORS - 1] of TRGBTriple; | |
procedure AddFrameGroup(newFrameGroup: TFrameGroup); | |
procedure AverageFrames(chIndex, fromFrame, toFrame: integer; dest: TMPFile); | |
procedure BinaryOp(file1, file2: TMPFile; ch1, ch2, frame1, frame2: integer; gain1, gain2: double; | |
resultFrame: integer); | |
procedure Close(Sender: TObject); | |
function CreateEmptyFrame(fromFile: TMPFile): integer; | |
procedure CopyChannelsToClipboard(bCh2, bCh3: boolean; fromFrame, toFrame: integer); | |
procedure CopyFrames(chIndex, fromFrame, toFrame: integer; dest: TMPFile); {from one file to a memory file, rect to rect} | |
procedure CloneROIs(ROIList: TROIList; fromIndex: integer); {duplicate each ROI but with opposite channel} | |
procedure DetectROIs(ROIList: TROIList; chIndex, fromFrame, toFrame, threshold, minArea, | |
templateFrom, templateTo: integer); | |
function DigitalToAnalog(chIndex, iValue: integer): double; | |
procedure DoBackgroundCorrection; | |
function GetAverage(frameIndex, chIndex: integer; rc: TRect): integer; | |
function GetROIAverageValue(ROIList: TROIList; roiIndex, frameIndex: integer): integer; | |
function GetPixelValue(frameIndex, chIndex, xData, yData: integer): int16; | |
function GetMax(frameIndex, chIndex: integer; rc: TRect; var x, y: integer): integer; | |
function GetMin(frameIndex, chIndex: integer; rc: TRect; var x, y: integer): integer; | |
function GetPropertyValue(propName: string): string; | |
function IsOperationOK(chIndex, fromFrame, toFrame: integer; dest: TMPFile): boolean; | |
procedure MakeAVIMovie(const avifilename: string; chIndex, fromFrame, toFrame, newframeRate: integer; | |
colorScheme: TColorScheme; fromViewer: TObject; bOverlayCh1on2: boolean); | |
function MakeTIFF(const avifilename: string; chIndex, fromFrame, toFrame: integer): boolean; | |
procedure NewAnalogWnd; | |
procedure NewViewer; | |
procedure OnNewFrames; | |
procedure OnWndClose(wnd: TForm); {when a viewer or analog wnd closes} | |
procedure SaveChannelsToFile(bASCII: boolean; fname: string; bCh2, bCh3: boolean; fromFrame, toFrame: integer); | |
function SizeOfFrameCompatible(width, height: integer): boolean; | |
procedure StackX(chIndex, fromFrame, toFrame, fromY, toY: integer; dest: TMPFile); | |
procedure StackY(chIndex, fromFrame, toFrame, fromX, toX: integer; dest: TMPFile); | |
procedure StackZ(chIndex, fromFrame, toFrame: integer; dest: TMPFile); | |
function SaveAs(const sFilename: string): TFileErr; | |
procedure SubtractFrame(chIndex, plusFrameIndex, minusFrameIndex: integer; dest: TMPFile); | |
constructor CreateFromTemplate(const sFilename: string; templateFile: TMPFile); | |
constructor CreateFromFile(const sFilename: string); | |
destructor Destroy; override; | |
property ActiveFrameIndex: integer read fActiveFrameIndex write SetActiveFrameIndex; | |
property AnalogChCount: integer read GetAnalogChCount; | |
property AnalogChEnabled[chIndex: integer]: boolean read GetAnalogChEnabled; | |
property AnalogWndCount: integer read GetAnalogWndCount; | |
property AnalogWnds[wndIndex: integer]: TForm read GetAnalogWnds; | |
property Angle: integer read fAngle; | |
property ChAcquisitionRate[chIndex: integer]: double read GetChAcquisitionRate; | |
property ChConvFactor[chIndex: integer]: double read GetChConvFactor; | |
property ChDataPtsPerFrame[chIndex: integer]: integer read GetChDataPtsPerFrame; | |
property ChEnabled[chIndex: integer]: boolean read GetChEnabled; | |
property ChInputRange[chIndex: integer]: TFullScaleVal read GetChInputRange; | |
property ChNames[chIndex: integer]: string read GetChNames; | |
property ChUnit[chIndex: integer]: string read GetChUnit; | |
property ChMaxPixelValues[chIndex: integer]: integer read GetChMaxPixelValues; | |
property ChPrefix[chIndex: integer]: TPrefix read GetChPrefix; | |
property ChOffset[chIndex: integer]: double read GetChOffset; | |
property Closing: boolean read fbClosing; {when user closes file from menu} | |
property Comments: string read sComments write sComments; | |
property DefaultVideoChannel: integer read GetDefaultVideoChannel; | |
property Filename: string read ffilename; | |
property FrameComment[frameIndex: integer]: string read GetFrameComment | |
write SetFrameComment; | |
property FrameCount: integer read GetFrameCount; | |
property FrameHeight: integer read fFrameHeight; | |
property FrameRate: double read GetFrameRate; {in frames per second} | |
property FrameSize: integer read GetFrameSize; {in samples} | |
property Frames[frameIndex: integer]: TFrameGroup read GetFrames; | |
property FrameWidth: integer read fFrameWidth; | |
property FullFrameSize: integer read GetFullFrameSize; {= Frame size + "forgotten pixels"} | |
property IsMemoryFile: boolean read fbIsMemoryFile; | |
property IsVideoChannel[chIndex: integer]: boolean read GetIsVideoChannel; | |
property LineRepeatCount: integer read fLineRepeatCount; | |
{ property LineForXScan: boolean read fbLineForXScan;} | |
property Magnification: double read fMagnification; | |
property MaxPixelValue: integer read GetMaxPixelValue; {255, 2047 or 32767} | |
property PixelClock: integer read fPixelClock; {in ns} | |
property Resolution: string read GetResolution; | |
property Rotation: integer read fRotation; | |
property VideoChCount: integer read GetVideoChCount; | |
property VideoChEnabled[chIndex: integer]: boolean read GetVideoChEnabled; | |
property ViewerCount: integer read GetViewerCount; | |
property Viewers[viewerIndex: integer]: TForm read GetViewers; | |
property ScanMode: TScanMode read fScanMode; | |
property StackAveragingCount: integer read fStackAveragingCount; | |
property StackFrameCount: integer read fStackFrameCount; | |
property StackInterval: double read fStackInterval; | |
property StackRepeatCount: integer read fStackRepeatCount; | |
property XFrameOffset: integer read fXFrameOffset; | |
property XStagePosition: integer read fXStagePosition; | |
property YFrameOffset: integer read fYFrameOffset; | |
property YStagePosition: integer read fYStagePosition; | |
property ZStagePosition: double read fZStagePosition; | |
end; | |
//------------------------------- FILE LIST --------------------------------- | |
{holds all the files} | |
TFileList = class(TStringList) | |
private | |
function IsMPFile(const sFilename: string): boolean; | |
function GetTemporaryFileName: string; | |
function Load(const sFilename: string): TFileErr; | |
public | |
dataDirectory: string; | |
procedure FillComboBoxWithWorkspaces(aComboBox: TComboBox); | |
procedure NotifyFileClosing(Sender: TMPFile); | |
procedure NewFile(templateFile: TMPFile); | |
procedure Open(const sFilename: string); | |
procedure SaveFileAs(mpFile: TMPFile; const newName: string); | |
function WorkspaceCount: integer; | |
destructor Destroy; override; | |
end; | |
function BoolToString(b: Boolean): string; | |
{function LineForXScanToString(bLine: boolean): string; OBSOLETE} | |
{function StringToLineForXScan(s: string): boolean;} | |
function ScanModeToString(smode: TScanMode): string; | |
function StringToScanMode(s: string): TScanMode; | |
function StringToBool(s: string): Boolean; | |
function StringToInputRange(s: string): TFullScaleVal; | |
function StringToPrefix(s: string): TPrefix; | |
function IntensityControlToString(ic: TIntensityControl): string; | |
{******************************************************************************} | |
{*} {*} | |
{*} IMPLEMENTATION {*} | |
{*} {*} | |
{******************************************************************************} | |
uses mainfrm, Math, analogu, vieweru, dialogs, Clipbrd; | |
const | |
TIFF_TAG_COUNT = 22; {Includes ImageDescription tag} | |
TIFF_ASCII = 2; | |
TIFF_SHORT = 3; | |
TIFF_LONG = 4; | |
TIFF_RATIONAL = 5; | |
TIFF_ImageDescription = 270; | |
FILE_PROP_COUNT = 74; {74 default properties per file in property set} | |
type | |
TTIFFHeader = packed record | |
order, | |
signature: Word; | |
IFDOffset: integer; | |
end; | |
TTagRecord = packed record | |
tagID, tagType: Word; | |
count, dataOffset: integer; | |
end; | |
TIFD = packed record | |
count: Word; | |
tagRecords: array[1..TIFF_TAG_COUNT] of TTagRecord; | |
nextIDFoffset: integer; | |
XNum, XDenom, | |
YNum, YDenom: integer; | |
end; | |
{followed by image description ASCII string} | |
const | |
TiffHeader: TTIFFHeader = (order: $4949; signature: 42; IFDOffset: 8); | |
OFLAGS = STGM_DIRECT or STGM_READWRITE or STGM_CREATE or STGM_SHARE_EXCLUSIVE; | |
RFLAGS = STGM_DIRECT or STGM_READ or STGM_SHARE_EXCLUSIVE; | |
FMTID_User_Defined_Properties: TGUID = '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}'; | |
sTIFFPropNames: string = | |
'Channel: %d' + #13#10 + | |
'Resolution: %s' + #13#10 + | |
'Scan Mode: %s' + #13#10 + | |
'X Stage Position (microns): %d' + #13#10 + | |
'Y Stage Position (microns): %d' + #13#10 + | |
'Z Stage Position (microns): %f' + #13#10 + | |
'Section Count: %d' + #13#10 + | |
'z- Interval (microns): %f' + #13#10 + | |
'Frames Per Section: %d' + #13#10 + | |
'Stack Repeat Count: %d' + #13#10 + | |
'Magnification: x%f' + #13#10 + | |
'Rotation (degrees): %d' + #13#10 + | |
'X Frame Offset (pixels): %d' + #13#10 + | |
'Y Frame Offset (pixels): %d' + #13#10 + | |
'Frame Rate (fps): %f'; | |
sPropNames: array[0..FILE_PROP_COUNT - 1] of string = ( | |
'Resolution', | |
'Scan Mode', | |
'X Frame Offset', | |
'Y Frame Offset', | |
'Frame Width', | |
'Frame Height', | |
'Pixel Clock', | |
'Channel name (1)', 'Enabled (1)', 'Input Range (1)', | |
'Channel name (2)', 'Enabled (2)', 'Input Range (2)', | |
'Channel name (3)', 'Enabled (3)', 'Input Range (3)', 'Channel Unit (3)', | |
'Channel Prefix (3)', 'Conversion factor (3)', 'Offset (3)', 'Data Points Per Frame (3)', | |
'Channel name (4)', 'Enabled (4)', 'Input Range (4)', 'Channel Unit (4)', | |
'Channel Prefix (4)', 'Conversion factor (4)', 'Offset (4)', 'Data Points Per Frame (4)', | |
'Frame Count', | |
'X Position', | |
'Y Position', | |
'Z Position', | |
'Section Count', | |
'z- Interval', | |
'Averaging Count', | |
'Repeat Count', | |
'Magnification', | |
'Rotation', | |
'Comments', | |
'Is Video Channel (3)', | |
'Is Video Channel (4)', | |
'z- Distance', | |
'Travel Duration', | |
'Fast Stack Repeat Count', | |
'Initial Intensity', | |
'Final Intensity', | |
'At Z- Distance', | |
'Intensity Control', | |
'Ch Max Pixel Value (1)', | |
'Ch Max Pixel Value (2)', | |
'Ch Max Pixel Value (3)', | |
'Ch Max Pixel Value (4)', {53 props} | |
slutType, | |
'Base Color (1)', | |
'Base Color (2)', | |
'Base Color (3)', | |
'Base Color (4)', | |
'Negative Color (1)', | |
'Negative Color (2)', | |
'Negative Color (3)', | |
'Negative Color (4)', | |
'MidRange Color (1)', | |
'MidRange Color (2)', | |
'MidRange Color (3)', | |
'MidRange Color (4)', | |
'Max Color (1)', | |
'Max Color (2)', | |
'Max Color (3)', | |
'Max Color (4)', | |
'Max Pixel Value of LUT (1)', | |
'Max Pixel Value of LUT (2)', | |
'Max Pixel Value of LUT (3)', | |
'Max Pixel Value of LUT (4)' | |
); | |
sAlreadyLoaded = 'File %s is already opened in MPView.'; | |
procedure MakeIFD(var IFD: TIFD); | |
begin | |
with IFD do | |
begin | |
count := TIFF_TAG_COUNT; | |
tagRecords[1].tagID := 254; {NewSubtitleType} | |
tagRecords[1].tagType := TIFF_LONG; | |
tagRecords[1].count := 1; | |
tagRecords[1].dataOffset := 0; | |
tagRecords[2].tagID := 256; {ImageWidth} | |
tagRecords[2].tagType := TIFF_LONG; | |
tagRecords[2].count := 1; | |
tagRecords[3].tagID := 257; {ImageLength} | |
tagRecords[3].tagType := TIFF_LONG; | |
tagRecords[3].count := 1; | |
tagRecords[4].tagID := 258; {BitsPerSample} | |
tagRecords[4].tagType := TIFF_SHORT; | |
tagRecords[4].count := 1; | |
tagRecords[4].dataOffset := 16; | |
tagRecords[5].tagID := 259; {Compression} | |
tagRecords[5].tagType := TIFF_SHORT; | |
tagRecords[5].count := 1; | |
tagRecords[5].dataOffset := 1; {No compression} | |
tagRecords[6].tagID := 262; {PhotometricInterpretation} | |
tagRecords[6].tagType := TIFF_SHORT; | |
tagRecords[6].count := 1; | |
tagRecords[6].dataOffset := 1; {BlackIsZero} | |
tagRecords[7].tagID := 263; {Tresholding} | |
tagRecords[7].tagType := TIFF_SHORT; | |
tagRecords[7].count := 1; | |
tagRecords[7].dataOffset := 1; | |
tagRecords[8].tagID := 266; {FillOrder} | |
tagRecords[8].tagType := TIFF_SHORT; | |
tagRecords[8].count := 1; | |
tagRecords[8].dataOffset := 1; | |
tagRecords[9].tagID := 273; {StripOffsets} | |
tagRecords[9].tagType := TIFF_LONG; | |
tagRecords[9].count := 1; | |
tagRecords[10].tagID := 274; {Orientation} | |
tagRecords[10].tagType := TIFF_SHORT; | |
tagRecords[10].count := 1; | |
tagRecords[10].dataOffset := 1; | |
tagRecords[11].tagID := 277; {SamplesPerPixel} | |
tagRecords[11].tagType := TIFF_SHORT; | |
tagRecords[11].count := 1; | |
tagRecords[11].dataOffset := 1; | |
tagRecords[12].tagID := 278; {RowsPerStrip} | |
tagRecords[12].tagType := TIFF_LONG; | |
tagRecords[12].count := 1; | |
tagRecords[13].tagID := 279; {StripByteCounts} | |
tagRecords[13].tagType := TIFF_LONG; | |
tagRecords[13].count := 1; | |
tagRecords[14].tagID := 280; {MinSampleValue} | |
tagRecords[14].tagType := TIFF_SHORT; | |
tagRecords[14].count := 1; | |
tagRecords[14].dataOffset := 0; | |
tagRecords[15].tagID := 281; {MaxSampleValue} | |
tagRecords[15].tagType := TIFF_SHORT; | |
tagRecords[15].count := 1; | |
tagRecords[15].dataOffset := 65535; | |
tagRecords[16].tagID := 282; {XResolution} | |
tagRecords[16].tagType := TIFF_RATIONAL; | |
tagRecords[16].count := 1; | |
tagRecords[17].tagID := 283; {YResolution} | |
tagRecords[17].tagType := TIFF_RATIONAL; | |
tagRecords[17].count := 1; | |
tagRecords[18].tagID := 284; {PlanarConfiguration} | |
tagRecords[18].tagType := TIFF_SHORT; | |
tagRecords[18].count := 1; | |
tagRecords[18].dataOffset := 1; {Chunky} | |
tagRecords[19].tagID := 290; {GrayResponseUnit} | |
tagRecords[19].tagType := TIFF_SHORT; | |
tagRecords[19].count := 1; | |
tagRecords[19].dataOffset := 1; | |
tagRecords[20].tagID := 296; {ResolutionUnit} | |
tagRecords[20].tagType := TIFF_SHORT; | |
tagRecords[20].count := 1; | |
tagRecords[20].dataOffset := 2; {Inch} | |
tagRecords[21].tagID := 339; {SampleFormat} | |
tagRecords[21].tagType := TIFF_SHORT; | |
tagRecords[21].count := 1; | |
tagRecords[21].dataOffset := 1; | |
tagRecords[22].tagID := TIFF_ImageDescription; | |
tagRecords[22].tagType := TIFF_ASCII; | |
XNum := 72; | |
XDenom := 1; | |
YNum := 72; | |
YDenom := 1; | |
end; | |
end; | |
{ | |
OBSOLETE FUNCTIONS | |
function LineForXScanToString(bLine: boolean): string; | |
begin | |
if bLine then Result := 'Line' else Result := 'Sine'; | |
end; | |
function StringToLineForXScan(s: string): boolean; | |
begin | |
Result := (s = 'Line'); | |
end;} | |
function ScanModeToString(smode: TScanMode): string; | |
begin | |
case smode of | |
SM_MOVIE: Result := 'Movie'; | |
SM_STACK: Result := 'Image Stack'; | |
{ SM_STACKMOVIE: Result := 'Image Stack Movie';} | |
SM_LINESCAN: Result := 'Line Scan'; | |
SM_REPEAT_LINESCAN: Result := 'Repeat Line Scan'; | |
SM_REGIONSCAN: Result := 'Region Scan'; | |
else Result := ''; | |
end | |
end; | |
function StringToScanMode(s: string): TScanMode; | |
begin | |
if s = 'Movie' then Result := SM_MOVIE else | |
if s = 'Image Stack' then Result := SM_STACK else | |
{ if s = 'Image Stack Movie' then Result := SM_STACKMOVIE else} | |
if s = 'Line Scan' then Result := SM_LINESCAN else | |
if s = 'Repeat Line Scan' then Result := SM_REPEAT_LINESCAN else | |
if s = 'Region Scan' then Result := SM_REGIONSCAN else | |
Result := SM_MOVIE; | |
end; | |
function BoolToString(b: Boolean): string; | |
begin | |
if b then Result := 'True' else Result := 'False'; | |
end; | |
function StringToBool(s: string): Boolean; | |
begin | |
Result := (s = 'True'); | |
end; | |
function StringToInputRange(s: string): TFullScaleVal; | |
begin | |
if s = Chr(177) + '42V' then Result := pm_42V else | |
if s = Chr(177) + '20V' then Result := pm_20V else | |
if s = Chr(177) + '10V' then Result := pm_10V else | |
if s = Chr(177) + '5V' then Result := pm_5V else | |
if s = Chr(177) + '2V' then Result := pm_2V else | |
if s = Chr(177) + '1V' then Result := pm_1V else | |
if s = Chr(177) + '0.5V' then Result := pm_0_5V else | |
if s = Chr(177) + '0.2V' then Result := pm_0_2V else | |
Result := pm_10V; | |
end; | |
function StringToPrefix(s: string): TPrefix; | |
begin | |
if s = 'x' then Result := tpXENNO else | |
if s = 'y' then Result := tpYOCTO else | |
if s = 'z' then Result := tpZEPTO else | |
if s = 'a' then Result := tpATTO else | |
if s = 'f' then Result := tpFEMTO else | |
if s = 'p' then Result := tpPICO else | |
if s = 'n' then Result := tpNANO else | |
if s = #181 then Result := tpMICRO else | |
if s = 'm' then Result := tpMILLI else | |
if s = '' then Result := tpUNITY else | |
if s = 'k' then Result := tpKILO else | |
if s = 'M' then Result := tpMEGA else | |
if s = 'G' then Result := tpGIGA else | |
if s = 'T' then Result := tpTERA else | |
if s = 'P' then Result := tpPETA else | |
if s = 'E' then Result := tpECTA else | |
if s = 'Z' then Result := tpZETTA else | |
if s = 'Y' then Result := tpYOTTA else | |
if s = 'X' then Result := tpXENNA else | |
Result := tpUNITY; | |
end; | |
//-------------------------------- FRAME -------------------------------------- | |
constructor TFrame.Create(mp_File: TMPFile; iChIndex, iFrameIndex: integer); | |
var i: integer; | |
begin | |
mpFile := mp_File; | |
frameIndex := iFrameIndex; | |
chIndex := iChIndex; | |
SetLength(data, mpFile.FrameWidth * mpFile.FrameHeight); | |
if mpFile.ScanMode = SM_REGIONSCAN then | |
for i := 0 to Length(data) - 1 do data[i] := 0; | |
end; | |
//------------------------------ VIDEO FRAME ---------------------------------- | |
function TVideoFrame.GetHeight: integer; | |
begin | |
Result := mpFile.FrameHeight; | |
end; | |
function TVideoFrame.GetPixels(x, y: integer): int16; | |
begin | |
Result := data[x + y * Width]; | |
end; | |
function TVideoFrame.GetWidth: integer; | |
begin | |
Result := mpFile.FrameWidth; | |
end; | |
procedure TVideoFrame.LoadFromFile(frameIndex: integer); | |
var libNewPosition: Largeint; | |
i: integer; | |
pt: TPoint; | |
tempData: array of int16; | |
begin | |
OleCheck(mpFile.chStreams[chIndex].Seek(frameIndex * mpFile.FrameSize * SizeOf(int16) | |
, STREAM_SEEK_SET, libNewPosition)); | |
if mpFile.ScanMode <> SM_REGIONSCAN then | |
OleCheck(mpFile.chStreams[chIndex].Read(@data[0], mpFile.FrameSize * SizeOf(int16), nil)) | |
else | |
begin | |
{Region scan: the frame is 512 x 512, we fill with data indexed by RegionPts} | |
SetLength(tempData, mpFile.FrameSize); | |
OleCheck(mpFile.chStreams[chIndex].Read(@tempData[0], mpFile.FrameSize * SizeOf(int16), nil)); | |
for i := 0 to mpFile.FrameSize - 1 do | |
begin | |
pt := mpFile.RegionPts[i]; | |
data[pt.x + pt.y * mpFile.FrameWidth] := tempData[i]; | |
end; | |
end; | |
end; | |
procedure TVideoFrame.SaveToFile; | |
begin | |
mpFile.chStreams[chIndex].Write(@data[0], Width * Height * SizeOf(int16), nil); | |
end; | |
procedure TVideoFrame.CopyData(dest: TVideoFrame); | |
var i: integer; | |
begin | |
for i := 0 to Width * Height - 1 do | |
dest.data[i] := data[i]; | |
end; | |
procedure TVideoFrame.GammaCorrection(blackLevel, whiteLevel: integer); | |
var i: integer; | |
maxPixelVal, pixelVal: int16; | |
begin | |
maxPixelVal := mpFile.ChMaxPixelValues[chIndex]; | |
for i := 0 to Width * Height - 1 do | |
begin | |
pixelVal := data[i]; | |
if pixelVal > whiteLevel then | |
pixelVal := maxPixelVal | |
else if pixelVal < blackLevel then | |
pixelVal := 0 | |
else | |
pixelVal := int16(Muldiv(integer(pixelVal) - blackLevel, maxPixelVal, | |
whiteLevel - blackLevel)); | |
data[i] := pixelVal; | |
end; | |
end; | |
procedure TVideoFrame.GetProfile(binSize: integer; var histogram: array of integer); | |
var binCount, i, j: integer; | |
begin | |
if (binSize <= 0) or (binSize > 1024) then Exit; | |
binCount := DEFAULT_MAX_PIXEL_VALUE + 1 div binSize + 1; | |
{ SetLength(histogram, binCount);} | |
for i := 0 to binCount - 1 do | |
histogram[i] := 0; | |
for i := 0 to Width * Height - 1 do | |
for j := 0 to binCount - 1 do | |
begin | |
if j = 0 then | |
begin | |
if data[i] < 0 then histogram[0] := histogram[0] + 1; | |
end | |
else | |
if (data[i] >= (j - 1) * binSize) and (data[i] < (j * binSize)) then | |
histogram[j] := histogram[j] + 1; | |
end; | |
end; | |
procedure TVideoFrame.CopyToDoubleArray(var dblArray: array of double); | |
var i: integer; | |
begin | |
for i := 0 to Width * Height - 1 do | |
dblArray[i] := data[i]; | |
end; | |
constructor TVideoFrame.Create(mp_File: TMPFile; iChIndex, iFrameIndex: integer); | |
begin | |
inherited Create(mp_File, ichIndex, iFrameIndex); | |
SetLength(data, mpFile.FrameWidth * mpFile.FrameHeight); | |
end; | |
///------------------------------ ANALOG FRAME --------------------------------- | |
function TAnalogFrame.SampleToAbsoluteTime(x: integer): double; {in seconds} | |
begin | |
Result := (frameIndex + x / mpFile.ChDataPtsPerFrame[chIndex]) / mpFile.FrameRate; | |
end; | |
function TAnalogFrame.GetIAnalogValue(x: integer): integer; | |
begin | |
Result := data[x]; | |
end; | |
function TAnalogFrame.GetfAnalogValue(x: integer): double; | |
begin | |
Result := mpFile.DigitalToAnalog(chIndex, data[x]); | |
end; | |
procedure TAnalogFrame.LoadFromFile(frameIndex: integer); | |
var libNewPosition: Largeint; | |
begin | |
mpFile.chStreams[chIndex].Seek(STREAM_SEEK_SET, | |
frameIndex * mpFile.ChDataPtsPerFrame[chIndex] * SizeOf(int16), libNewPosition); | |
mpFile.chStreams[chIndex].Read(@data[0], mpFile.ChDataPtsPerFrame[chIndex] * SizeOf(int16), nil); | |
end; | |
constructor TAnalogFrame.Create(mp_File: TMPFile; iChIndex, iFrameIndex: integer); | |
begin | |
inherited Create(mp_File, ichIndex, iFrameIndex); | |
SetLength(data, mpFile.fChDataPtsPerFrames[iChIndex]); | |
end; | |
//--------------------------- FRAME COMMENT LIST ------------------------------ | |
procedure TFrameCommentList.SaveFrameComments; | |
var commentStream: IStream; | |
i, j: integer; | |
s: string; | |
begin | |
if Count > 0 then | |
if Succeeded(mpFile.rootStorage.CreateStream('Frame comments', OFLAGS, 0, 0, commentStream)) then | |
begin | |
j := Count - 1; | |
commentStream.Write(@j, SizeOf(j), nil); | |
for i := 0 to Count - 1 do | |
begin | |
j := Integer(Objects[i]); | |
commentStream.Write(@j, SizeOf(j), nil); | |
j := Length(Strings[i]); | |
commentStream.Write(@j, SizeOf(j), nil); | |
s := Strings[i]; | |
commentStream.Write(@s[1], j, nil); | |
end; | |
commentStream := nil; | |
end; | |
end; | |
procedure TFrameCommentList.LoadFrameComments; | |
var commentStream: IStream; | |
i, frameIndex, stringLength, frameCount: integer; | |
s: string; | |
begin | |
if Succeeded(mpFile.rootStorage.OpenStream('Frame comments', nil, RFLAGS, 0, commentStream)) then | |
begin | |
commentStream.Read(@frameCount, SizeOf(frameCount), nil); | |
if frameCount >= 0 then | |
for i := 0 to frameCount do | |
begin | |
commentStream.Read(@frameIndex, SizeOf(frameIndex), nil); | |
commentStream.Read(@stringLength, SizeOf(stringLength), nil); | |
if stringLength > 0 then | |
begin | |
SetLength(s, stringLength); | |
commentStream.Read(@s[1], stringLength, nil); | |
AddObject(s, TObject(frameIndex)); | |
end; | |
end; | |
commentStream := nil; | |
end; | |
end; | |
function TFrameCommentList.GetFrameComment(frameIndex: integer): string; | |
begin | |
Result := ''; | |
if (Count > 0) and (IndexOfObject(TObject(frameIndex)) >= 0) then | |
Result := Strings[IndexOfObject(TObject(frameIndex))]; | |
end; | |
procedure TFrameCommentList.SetFrameComment(frameIndex: integer; const frameComment: string); | |
begin | |
if IndexOfObject(TObject(frameIndex)) >= 0 then | |
Strings[IndexOfObject(TObject(frameIndex))] := frameComment | |
else | |
AddObject(frameComment, TObject(frameIndex)); | |
end; | |
constructor TFrameCommentList.Create(theMPFile: TMPFile); | |
begin | |
mpFile := theMPFile; | |
end; | |
//------------------------------ FRAME GROUP ---------------------------------- | |
procedure TFrameGroup.LoadFromFile(frameIndex: integer); | |
var i: integer; | |
begin | |
for i := 0 to MAX_CH - 1 do | |
if channels[i] <> nil then | |
channels[i].LoadFromFile(frameIndex); | |
end; | |
procedure TFrameGroup.SetFrameIndex(newIndex: integer); | |
var i: integer; | |
begin | |
fFrameIndex := newIndex; | |
for i := 0 to MAX_CH - 1 do | |
if channels[i] <> nil then channels[i].frameIndex := newIndex; | |
end; | |
procedure TFrameGroup.SetFrameWidth(newWidth: integer); | |
begin | |
fWidth := newWidth; | |
end; | |
procedure TFrameGroup.SetFrameHeight(newHeight: integer); | |
begin | |
fHeight := newHeight; | |
if channels[0] <> nil then SetLength(channels[0].data, fWidth * fHeight); | |
if channels[1] <> nil then SetLength(channels[1].data, fWidth * fHeight); | |
if mpFile.IsVideoChannel[2] and (channels[2] <> nil) then SetLength(channels[2].data, fWidth * fHeight); | |
if mpFile.IsVideoChannel[3] and (channels[3] <> nil) then SetLength(channels[3].data, fWidth * fHeight); | |
if mpFile.AnalogChEnabled[2] and (channels[2] <> nil) then SetLength(channels[2].data, mpFile.ChDataPtsPerFrame[2]); | |
if mpFile.AnalogChEnabled[3] and (channels[3] <> nil) then SetLength(channels[3].data, mpFile.ChDataPtsPerFrame[3]); | |
end; | |
constructor TFrameGroup.Create(mp_file: TMPFile); | |
var i: integer; | |
begin | |
mpFile := mp_file; | |
for i := 0 to MAX_CH - 1 do | |
if mpFile.VideoChEnabled[i] then | |
channels[i] := TVideoFrame.Create(mpFile, i, fFrameIndex) | |
else if mpFile.AnalogChEnabled[i] then | |
channels[i] := TAnalogFrame.Create(mpFile, i, fFrameIndex); | |
end; | |
constructor TFrameGroup.CreateTempFrameGroup(mp_file: TMPFile); | |
begin | |
mpFile := mp_file; | |
channels[0] := TVideoFrame.Create(mpFile, 0, 0); | |
{ SetLength(channels[0].data, width * height);} | |
end; | |
constructor TFrameGroup.CreateForOp(mp_file: TMPFile); | |
begin | |
mpFile := mp_file; | |
channels[0] := TVideoFrame.Create(mpFile, 0, fFrameIndex); | |
{ SetLength(channels[0].data, width * height);} | |
end; | |
destructor TFrameGroup.Destroy; | |
var i: integer; | |
begin | |
for i := 0 to MAX_CH - 1 do | |
channels[i].Free; | |
inherited Destroy; | |
end; | |
//-------------------------------- FILE OBJECT -------------------------------- | |
//--------------------------- FILE OBJECT: PRIVATE ----------------------------- | |
procedure TMPFile.AdjustFrameCount; | |
var statstg: TStatStg; | |
validCh: integer; | |
begin | |
if VideoChEnabled[0] then validCh := 0 | |
else if VideoChEnabled[1] then validCh := 1 | |
else if VideoChEnabled[2] then validCh := 2 | |
else validCh := 3; | |
chStreams[validCh].Stat(statstg, STATFLAG_NONAME); | |
fFrameCount := statstg.cbSize div (FrameWidth * FrameHeight * SizeOf(int16)); | |
end; | |
function TMPFile.GetAnalogChCount: integer; | |
begin | |
Result := 0; | |
if fChEnabled[2] and not fIsVideoCh[2] then Result := 1; | |
if fChEnabled[3] and not fIsVideoCh[3] then Result := Result + 1; | |
end; | |
function TMPFile.GetAnalogChEnabled(chIndex: integer): boolean; | |
begin | |
if (chIndex <> 2) and (chIndex <> 3) then | |
Result := False | |
else | |
Result := fChEnabled[chIndex] and not fIsVideoCh[chIndex]; | |
end; | |
function TMPFile.GetAnalogWndCount: integer; | |
begin | |
if analogWndList <> nil then | |
Result := analogWndList.Count | |
else | |
Result := 0; | |
end; | |
function TMPFile.GetAnalogWnds(wndIndex: integer): TForm; | |
begin | |
Result := nil; | |
if (wndIndex >= 0) and (wndIndex < analogWndList.Count) then | |
Result := TForm(analogWndList.Items[wndIndex]); | |
end; | |
function TMPFile.GetChAcquisitionRate(chIndex: integer): double; | |
begin | |
Result := FrameRate / fChDataPtsPerFrames[chIndex]; | |
end; | |
function TMPFile.GetChConvFactor(chIndex: integer): double; | |
begin | |
Result := fChConvFactors[chIndex]; | |
end; | |
function TMPFile.GetChDataPtsPerFrame(chIndex: integer): integer; | |
begin | |
Result := fChDataPtsPerFrames[chIndex]; | |
end; | |
function TMPFile.GetChEnabled(chIndex: integer): boolean; | |
begin | |
Result := fChEnabled[chIndex]; | |
end; | |
function TMPFile.GetChInputRange(chIndex: integer): TFullScaleVal; | |
begin | |
Result := fChInputRanges[chIndex]; | |
end; | |
function TMPFile.GetChMaxPixelValues(chIndex: integer): integer; | |
begin | |
Result := fChMaxPixelValues[chIndex]; | |
end; | |
function TMPFile.GetChNames(chIndex: integer): string; | |
begin | |
Result := fChNames[chIndex]; | |
end; | |
function TMPFile.GetChUnit(chIndex: integer): string; | |
begin | |
Result := fChUnits[chIndex]; | |
end; | |
function TMPFile.GetChPrefix(chIndex: integer): TPrefix; | |
begin | |
Result := fChPrefixes[chIndex]; | |
end; | |
function TMPFile.GetChOffset(chIndex: integer): double; | |
begin | |
Result := fChOffsets[chIndex]; | |
end; | |
function TMPFile.GetDefaultVideoChannel: integer; | |
begin | |
if VideoChEnabled[0] then Result := 0 | |
else if VideoChEnabled[1] then Result := 1 | |
else if VideoChEnabled[2] then Result := 2 | |
else Result := 3; | |
end; | |
function TMPFile.GetFrameComment(frameIndex: integer): string; | |
begin | |
Result := frameCommentList.FrameComment[frameIndex]; | |
end; | |
function TMPFile.GetFrameCount: integer; | |
begin | |
if IsMemoryFile then | |
Result := frameGroupList.Count | |
else | |
Result := fFrameCount; | |
end; | |
function TMPFile.GetFrameRate: double; {in frames per seconds} | |
begin | |
{50 ns = 5e-8 s per pixel clock unit} | |
if ScanMode <> SM_REGIONSCAN then | |
Result := 1 / (Muldiv(5, fFrameWidth, 4) * fFrameHeight * fPixelClock * BASE_CLOCK) | |
else | |
Result := 1 / (FrameSize * fPixelClock * BASE_CLOCK); | |
end; | |
function TMPFile.GetFrameSize: integer; | |
begin | |
if ScanMode <> SM_REGIONSCAN then | |
Result := FrameWidth * FrameHeight | |
else | |
Result := Length(RegionPts); | |
end; | |
function TMPFile.GetFrames(frameIndex: integer): TFrameGroup; | |
begin | |
Result := nil; | |
if (frameIndex >= 0) and (frameIndex < FrameCount) then | |
if IsMemoryFile then | |
Result := TFrameGroup(frameGroupList.Items[frameIndex]) | |
else | |
begin | |
ActiveFrameIndex := frameIndex; | |
Result := fCurrentFrameGroup; | |
end; | |
end; | |
{returns the size of the frame if turnaround points (20% of number of pixels in | |
line scans)are included} | |
function TMPFile.GetFullFrameSize: integer; | |
begin | |
case ScanMode of | |
SM_MOVIE, SM_LINESCAN, SM_STACK, SM_FASTSTACK: Result := Muldiv(5, FrameSize, 4); | |
else Result := FrameSize; | |
end; | |
end; | |
function TMPFile.GetIsVideoChannel(chIndex: integer): boolean; | |
begin | |
if (chIndex = 0) or (chIndex = 1) then | |
Result := True | |
else if (chIndex = 2) or (chIndex = 3) then | |
Result := fIsVideoCh[chIndex] | |
else | |
Result := False; | |
end; | |
function TMPFile.GetMaxPixelValue: integer; | |
begin | |
case fResolution of | |
RESOLUTION_8_BITS: Result := 255; | |
RESOLUTION_12_BITS: Result := DEFAULT_MAX_PIXEL_VALUE; | |
else Result := 32767; | |
end; | |
end; | |
procedure TMPFile.GetRegions; | |
var regionStream: IStream; | |
statstg: TStatStg; | |
regionSize: integer; | |
libNewPosition: Largeint; | |
begin | |
{opens the stream 'Regions'} | |
OleCheck(rootStorage.OpenStream('Regions', nil, RFLAGS, 0, regionStream)); | |
{gets the size of the stream} | |
regionStream.Stat(statstg, STATFLAG_NONAME); | |
regionSize := statStg.cbSize; | |
OleCheck(regionStream.Seek(0, STREAM_SEEK_SET, libNewPosition)); | |
SetLength(RegionPts, regionSize div SizeOf(TPoint)); | |
OleCheck(regionStream.Read(@RegionPts[0], regionSize, nil)); | |
end; | |
function TMPFile.GetResolution: string; | |
begin | |
case fResolution of | |
RESOLUTION_8_BITS: Result := '8-bit'; | |
RESOLUTION_12_BITS: Result := '12-bit'; | |
else Result := '16-bit'; | |
end; | |
end; | |
function TMPFile.GetVideoChCount: integer; | |
begin | |
Result := 0; | |
if fChEnabled[0] then Result := 1; | |
if fChEnabled[1] then Result := Result + 1; | |
if fChEnabled[2] and fIsVideoCh[2] then Result := Result + 1; | |
if fChEnabled[3] and fIsVideoCh[3] then Result := Result + 1; | |
end; | |
function TMPFile.GetVideoChEnabled(chIndex: integer): boolean; | |
begin | |
if (chIndex = 0) or (chIndex = 1) then | |
Result := fChEnabled[chIndex] | |
else | |
Result := fChEnabled[chIndex] and fIsVideoCh[chIndex]; | |
end; | |
function TMPFile.GetViewerCount: integer; | |
begin | |
Result := viewerList.Count; | |
end; | |
function TMPFile.GetViewers(viewerIndex: integer): TForm; | |
begin | |
if (viewerIndex >= 0) and (viewerIndex < viewerList.Count) then | |
Result := TForm(viewerList.Items[viewerIndex]) | |
else | |
Result := nil; | |
end; | |
procedure TMPFile.InitializeColors; | |
var i: integer; | |
begin | |
baseColors[0][0] := True; {Red} | |
baseColors[0][1] := False; | |
baseColors[0][2] := False; | |
baseColors[1][0] := False; | |
baseColors[1][1] := True; | |
baseColors[1][2] := False; | |
baseColors[2][0] := False; | |
baseColors[2][1] := False; | |
baseColors[2][2] := True; | |
baseColors[3][0] := False; | |
baseColors[3][1] := True; | |
baseColors[3][2] := True; | |
negativeColors[0].rgbtRed := 0; negativeColors[0].rgbtGreen := 0; negativeColors[0].rgbtBlue := 255; | |
midRangeColors[0].rgbtRed := 0; midRangeColors[0].rgbtGreen := 255; midRangeColors[0].rgbtBlue := 0; | |
maxColors[0].rgbtRed := 255; maxColors[0].rgbtGreen := 0; maxColors[0].rgbtBlue := 0; | |
negativeColors[1].rgbtRed := 0; negativeColors[1].rgbtGreen := 255; negativeColors[1].rgbtBlue := 0; | |
midRangeColors[1].rgbtRed := 0; midRangeColors[1].rgbtGreen := 255; midRangeColors[1].rgbtBlue := 255; | |
maxColors[1].rgbtRed := 255; maxColors[1].rgbtGreen := 0; maxColors[1].rgbtBlue := 0; | |
negativeColors[2].rgbtRed := 0; negativeColors[2].rgbtGreen := 255; negativeColors[2].rgbtBlue := 0; | |
midRangeColors[2].rgbtRed := 0; midRangeColors[2].rgbtGreen := 255; midRangeColors[2].rgbtBlue := 255; | |
maxColors[2].rgbtRed := 255; maxColors[2].rgbtGreen := 0; maxColors[2].rgbtBlue := 0; | |
negativeColors[3].rgbtRed := 0; negativeColors[3].rgbtGreen := 255; negativeColors[3].rgbtBlue := 0; | |
midRangeColors[3].rgbtRed := 0; midRangeColors[3].rgbtGreen := 255; midRangeColors[3].rgbtBlue := 255; | |
maxColors[3].rgbtRed := 255; maxColors[3].rgbtGreen := 0; maxColors[3].rgbtBlue := 0; | |
for i := 0 to MAX_CH - 1 do MaxPixels[i] := 2047; | |
end; | |
procedure TMPFile.LoadFrameGroup(newIndex: integer); | |
begin | |
fCurrentFrameGroup.LoadFromFile(newIndex); | |
end; | |
type | |
TPropSpecArray = array[0..1000] of TPropSpec; | |
TPropVariantArray = array[0..1000] of TPropVariant; | |
TpPropSpecArray = ^TPropSpecArray; | |
TpPropVariantArray = ^TPropVariantArray; | |
function IntensityControlToString(ic: TIntensityControl): string; | |
begin | |
if ic = IC_NO_CONTROL then | |
Result := 'No Control' | |
else if ic = IC_LINEAR then | |
Result := 'Linear' | |
else | |
Result := 'Exponential'; | |
end; | |
function StringToIntensityControl(s: string): TIntensityControl; | |
begin | |
if s = 'No Control' then | |
Result := IC_NO_CONTROL | |
else if s = 'Linear' then | |
Result := IC_LINEAR | |
else | |
Result := IC_EXPONENTIAL; | |
end; | |
procedure TMPFile.ReadPropertySet; | |
var ps: TpPropSpecArray; | |
pv: TpPropVariantArray; | |
i: integer; | |
s: string; | |
begin | |
ps := nil; pv := nil; | |
try | |
GetMem(ps, FILE_PROP_COUNT * SizeOf(TPropSpec)); | |
GetMem(pv, FILE_PROP_COUNT * SizeOf(TPropVariant)); | |
for i := 0 to FILE_PROP_COUNT - 1 do | |
begin | |
ps^[i].ulKind := PRSPEC_LPWSTR; | |
ps^[i].lpwstr := StringToOLEStr(sPropNames[i]); | |
end; | |
OleCheck(propertyStorage.ReadMultiple(FILE_PROP_COUNT, @ps[0], @pv[0])); | |
if (pv^[0].pwszVal <> nil) and (WideCharToString(pv^[0].pwszVal) = '16-bit') then | |
fResolution := RESOLUTION_16_BITS | |
else fResolution := RESOLUTION_12_BITS; | |
if fResolution = RESOLUTION_12_BITS then | |
for i := 0 to MAX_CH - 1 do fChMaxPixelValues[i] := DEFAULT_MAX_PIXEL_VALUE | |
else | |
for i := 0 to MAX_CH - 1 do fChMaxPixelValues[i] := 32767; | |
if pv^[1].pwszVal = nil then s := '' else | |
s := WideCharToString(pv^[1].pwszVal); {Scan Mode} | |
fScanMode := StringToScanMode(s); | |
{ s := WideCharToString(pv^[2].pwszVal);} {Line Scan Mode} | |
{ fbLineForXScan := StringToLineForXScan(s);} | |
if pv^[2].pwszVal = nil then s := '' else | |
s := WideCharToString(pv^[2].pwszVal); {X Frame Offset'} | |
if s = '' then s := '0'; fXFrameOffset := StrToInt(s); | |
if pv^[3].pwszVal = nil then s := '' else | |
s := WideCharToString(pv^[3].pwszVal); {Y Frame Offset'} | |
if s = '' then s := '0'; fYFrameOffset := StrToInt(s); | |
if pv^[4].pwszVal = nil then s := '' else | |
s := WideCharToString(pv^[4].pwszVal); {Frame Width'} | |
if s = '' then s := '0'; fFrameWidth := StrToInt(s); | |
if pv^[5].pwszVal = nil then s := '' else | |
s := WideCharToString(pv^[5].pwszVal); {Frame Height} | |
if s = '' then s := '0'; fFrameHeight := StrToInt(s); | |
if pv^[6].pwszVal = nil then s := '20' else | |
s := WideCharToString(pv^[6].pwszVal); {Pixel Clock} | |
if s = '' then s := '0'; fPixelClock := StrToInt(s); | |
if pv^[7].pwszVal = nil then fChNames[0] := 'Channel 1' else | |
fChNames[0] := WideCharToString(pv^[7].pwszVal); {Channel name (1)} | |
if pv^[8].pwszVal = nil then fChEnabled[0] := False else | |
fChEnabled[0] := StringToBool(WideCharToString(pv^[8].pwszVal)); {Enabled (1)} | |
if pv^[9].pwszVal = nil then fChInputRanges[0] := pm_10V else | |
fChInputRanges[0] := StringToInputRange(WideCharToString(pv^[9].pwszVal)); {Input Range (1)} | |
if pv^[10].pwszVal = nil then fChNames[1] := 'Channel 2' else | |
fChNames[1] := WideCharToString(pv^[10].pwszVal); {Channel name (2)} | |
if pv^[11].pwszVal = nil then fChEnabled[1] := False else | |
fChEnabled[1] := StringToBool(WideCharToString(pv^[11].pwszVal)); {Enabled (2)} | |
if pv^[12].pwszVal = nil then fChInputRanges[1] := pm_10V else | |
fChInputRanges[1] := StringToInputRange(WideCharToString(pv^[12].pwszVal)); {Input Range (2)} | |
if pv^[13].pwszVal = nil then fChNames[2] := 'Channel 3' else | |
fChNames[2] := WideCharToString(pv^[13].pwszVal); {Channel name (3)} | |
if pv^[14].pwszVal = nil then fChEnabled[2] := False else | |
fChEnabled[2] := StringToBool(WideCharToString(pv^[14].pwszVal)); {Enabled (3)} | |
if pv^[15].pwszVal = nil then fChInputRanges[2] := pm_10V else | |
fChInputRanges[2] := StringToInputRange(WideCharToString(pv^[15].pwszVal)); {Input Range (3)} | |
if pv^[16].pwszVal = nil then fChInputRanges[2] := pm_10V else | |
fChUnits[2] := WideCharToString(pv^[16].pwszVal); {Channel Unit (3)} | |
if pv^[17].pwszVal = nil then fChPrefixes[2] := tpUNITY else | |
fChPrefixes[2] := StringToPrefix(WideCharToString(pv^[17].pwszVal)); {Channel Prefix (3)} | |
if pv^[18].pwszVal = nil then s := '1' else | |
s := WideCharToString(pv^[18].pwszVal); {Conversion factor (3)} | |
if s = '' then s := '0'; fChConvFactors[2] := StrToFloat(s); | |
if pv^[19].pwszVal = nil then s := '' else | |
s := WideCharToString(pv^[19].pwszVal); {Offset (3)} | |
if s = '' then s := '0'; fChOffsets[2] := StrToFloat(s); | |
if pv^[20].pwszVal = nil then s := '' else | |
s := WideCharToString(pv^[20].pwszVal); {Data Points Per Frame (3)} | |
if s = '' then s := '0'; fChDataPtsPerFrames[2] := StrToInt(s); | |
if pv^[21].pwszVal = nil then fChNames[3] := 'Channel 4' else | |
fChNames[3] := WideCharToString(pv^[21].pwszVal); {Channel name (4)} | |
if pv^[22].pwszVal = nil then fChEnabled[3] := False else | |
fChEnabled[3] := StringToBool(WideCharToString(pv^[22].pwszVal)); {Enabled (4)} | |
if pv^[23].pwszVal = nil then fChInputRanges[3] := pm_10V else | |
fChInputRanges[3] := StringToInputRange(WideCharToString(pv^[23].pwszVal)); {Input Range (4)} | |
if pv^[24].pwszVal = nil then fChUnits[3] := 'V' else | |
fChUnits[3] := WideCharToString(pv^[24].pwszVal); {Channel Unit (4)} | |
if pv^[25].pwszVal = nil then fChPrefixes[3] := tpUNITY else | |
fChPrefixes[3] := StringToPrefix(WideCharToString(pv^[25].pwszVal)); {Channel Prefix (4)} | |
if pv^[26].pwszVal = nil then s := '1' else | |
s := WideCharToString(pv^[26].pwszVal); {Conversion factor (4)} | |
if s = '' then s := '0'; fChConvFactors[3] := StrToFloat(s); | |
if pv^[27].pwszVal = nil then s := '0' else | |
s := WideCharToString(pv^[27].pwszVal); {Offset (4)} | |
if s = '' then s := '0'; fChOffsets[3] := StrToFloat(s); | |
if pv^[28].pwszVal = nil then s := '0' else | |
s := WideCharToString(pv^[28].pwszVal); {Data Points Per Frame (4)} | |
if s = '' then s := '0'; fChDataPtsPerFrames[3] := StrToInt(s); | |
if pv^[29].pwszVal = nil then s := '1' else | |
s := WideCharToString(pv^[29].pwszVal); {Frame Count'} | |
if s = '' then s := '0'; fFrameCount := StrToInt(s); | |
if pv^[30].pwszVal = nil then s := '0' else | |
s := WideCharToString(pv^[30].pwszVal); {X Position'} | |
if s = '' then s := '0'; fXStagePosition := StrToInt(s); | |
if pv^[31].pwszVal = nil then s := '0' else | |
s := WideCharToString(pv^[31].pwszVal); {Y Position'} | |
if s = '' then s := '0'; fYStagePosition := StrToInt(s); | |
if pv^[32].pwszVal = nil then s := '0' else | |
s := WideCharToString(pv^[32].pwszVal); {Z Position'} | |
if s = '' then s := '0'; fZStagePosition := StrToInt(s); | |
if pv^[33].pwszVal = nil then s := '1' else | |
s := WideCharToString(pv^[33].pwszVal); {Stack Count'} | |
if s = '' then s := '0'; fStackFrameCount := StrToInt(s); | |
if pv^[34].pwszVal = nil then s := '1' else | |
s := WideCharToString(pv^[34].pwszVal); {z- Interval'} | |
if s = '' then s := '0'; fStackInterval := StrToFloat(s); | |
if pv^[35].pwszVal = nil then s := '1' else | |
s := WideCharToString(pv^[35].pwszVal); {Averaging Count'} | |
if s = '' then s := '0'; fStackAveragingCount := StrToInt(s); | |
if pv^[36].pwszVal = nil then s := '1' else | |
s := WideCharToString(pv^[36].pwszVal); {Repeat Count'} | |
if s = '' then s := '0'; fStackRepeatCount := StrToInt(s); | |
if pv^[37].pwszVal = nil then s := 'x1.0' else | |
s := WideCharToString(pv^[37].pwszVal); {Magnification - remove 'x'} | |
s := Copy(s, 2, Length(s) - 1); if s = '' then s := '1'; fMagnification := StrToFloat(s); | |
if pv^[38].pwszVal = nil then s := '0' else | |
s := WideCharToString(pv^[38].pwszVal); {Rotation'} | |
if s = '' then s := '0'; fRotation := StrToInt(s); | |
if pv^[39].pwszVal = nil then sComments := '' else | |
sComments := WideCharToString(pv^[39].pwszVal); {Comments} | |
if pv^[40].pwszVal = nil then fIsVideoCh[2] := False else | |
fIsVideoCh[2] := StringToBool( | |
WideCharToString(pv^[40].pwszVal)); {Is Video Channel (3)} | |
if pv^[41].pwszVal = nil then fIsVideoCh[3] := False else | |
fIsVideoCh[3] := StringToBool( | |
WideCharToString(pv^[41].pwszVal)); {Is Video Channel (4)} | |
if pv^[42].pwszVal = nil then fzDistance := 0 else | |
fzDistance := StrToFloat( | |
WideCharToString(pv^[42].pwszVal)); {z- Distance} | |
if pv^[43].pwszVal = nil then fTravelDuration := '0 s' else | |
fTravelDuration := WideCharToString(pv^[43].pwszVal); {Travel Duration} | |
if pv^[44].pwszVal = nil then fFastStackRepeatCount := 0 else | |
fFastStackRepeatCount := StrToInt( | |
WideCharToString(pv^[44].pwszVal)); {Fast Stack Repeat Count} | |
if pv^[45].pwszVal = nil then fInitialIntensity := 0 else | |
fInitialIntensity := StrToInt( | |
WideCharToString(pv^[45].pwszVal)); {Initial Intensity} | |
if pv^[46].pwszVal = nil then fFinalIntensity := 0 else | |
fFinalIntensity := StrToInt( | |
WideCharToString(pv^[46].pwszVal)); {Final Intensity} | |
if pv^[47].pwszVal = nil then fAtZDistance := 0 else | |
fAtZDistance := StrToFloat( | |
WideCharToString(pv^[47].pwszVal)); {At Z- Distance} | |
if pv^[48].pwszVal = nil then fIntensityControl := IC_NO_CONTROL else | |
fIntensityControl := StringToIntensityControl( | |
WideCharToString(pv^[48].pwszVal)); {Intensity Control} | |
for i := 0 to MAX_CH - 1 do | |
if pv^[49 + i].pwszVal <> nil then | |
try | |
fChMaxPixelValues[i] := StrToInt(WideCharToString(pv^[49 + i].pwszVal)); | |
except | |
fChMaxPixelValues[i] := DEFAULT_MAX_PIXEL_VALUE; | |
end; | |
finally | |
if ps <> nil then Freemem(ps); | |
if pv <> nil then Freemem(pv); | |
end; | |
end; | |
procedure TMPFile.SetActiveFrameIndex(newIndex: integer); | |
begin | |
if (newIndex >= 0) and (newIndex < FrameCount) then | |
if newIndex <> fActiveFrameIndex then | |
begin | |
if not IsMemoryFile then LoadFrameGroup(newIndex); | |
fActiveFrameIndex := newIndex; | |
end; | |
end; | |
procedure TMPFile.SetFrameComment(frameIndex: integer; sComments: string); | |
begin | |
frameCommentList.FrameComment[frameIndex] := sComments; | |
end; | |
procedure TMPFile.WritePropertySet; | |
var ps: TpPropSpecArray; | |
pv: TpPropVariantArray; | |
i: integer; | |
sPropValues: array[0..FILE_PROP_COUNT - 1] of string; | |
begin | |
sPropValues[0] := Resolution; | |
sPropValues[1] := ScanModeToString(ScanMode); {Scan Mode} | |
sPropValues[2] := IntToStr(XFrameOffset); {X Frame Offset'} | |
sPropValues[3] := IntToStr(YFrameOffset); {Y Frame Offset'} | |
sPropValues[4] := IntToStr(FrameWidth); {Frame Width'} | |
sPropValues[5] := IntToStr(FrameHeight); {Frame Height} | |
sPropValues[6] := IntToStr(PixelClock); {Pixel Clock} | |
sPropValues[7] := ChNames[0]; {Channel name (1)} | |
sPropValues[8] := BoolToString(ChEnabled[0]); {Enabled (1)} | |
sPropValues[9] := InputRangeToString(ChInputRange[0]); {Input Range (1)} | |
sPropValues[10] := ChNames[1]; {Channel name (2)} | |
sPropValues[11] := BoolToString(ChEnabled[1]); {Enabled (2)} | |
sPropValues[12] := InputRangeToString(ChInputRange[1]); {Input Range (2)} | |
sPropValues[13] := ChNames[2]; {Channel name (3)} | |
sPropValues[14] := BoolToString(ChEnabled[2]); {Enabled (3)} | |
sPropValues[15] := InputRangeToString(ChInputRange[2]); {Input Range (3)} | |
sPropValues[16] := ChUnit[2]; {Channel Unit (3)} | |
sPropValues[17] := PrefixToString(ChPrefix[2]); {Channel Prefix (3)} | |
sPropValues[18] := FloatToStr(ChConvFactor[2]); {Conversion factor (3)} | |
sPropValues[19] := FloatToStr(ChOffset[2]); {Offset (3)} | |
sPropValues[20] := IntToStr(ChDataPtsPerFrame[2]); {Data Points Per Frame (3)} | |
sPropValues[21] := ChNames[3]; {Channel name (4)} | |
sPropValues[22] := BoolToString(ChEnabled[3]); {Enabled (4)} | |
sPropValues[23] := InputRangeToString(ChInputRange[3]); {Input Range (4)} | |
sPropValues[24] := ChUnit[3]; {Channel Unit (4)} | |
sPropValues[25] := PrefixToString(ChPrefix[3]); {Channel Prefix (4)} | |
sPropValues[26] := FloatToStr(ChConvFactor[3]); {Conversion factor (4)} | |
sPropValues[27] := FloatToStr(ChOffset[3]);{Offset (4)} | |
sPropValues[28] := IntToStr(ChDataPtsPerFrame[3]); {Data Points Per Frame (4)} | |
sPropValues[29] := IntToStr(FrameCount); {Frame Count'} | |
sPropValues[30] := IntToStr(XStagePosition); {X Position'} | |
sPropValues[31] := IntToStr(YStagePosition); {Y Position'} | |
sPropValues[32] := FloatToStr(ZStagePosition); {Z Position'} | |
sPropValues[33] := IntToStr(StackFrameCount); {Stack Count'} | |
sPropValues[34] := FloatToStr(StackInterval); {z- Interval'} | |
sPropValues[35] := IntToStr(StackAveragingCount); {Averaging Count'} | |
sPropValues[36] := IntToStr(StackRepeatCount); {Repeat Count'} | |
sPropValues[37] := 'x' + FloatToStr(Magnification); {Magnification'} | |
sPropValues[38] := IntToStr(Rotation); {Rotation'} | |
sPropValues[39] := sComments; {Comments} | |
sPropValues[40] := BoolToString(fIsVideoCh[2]); {Is Video Channel (3)} | |
sPropValues[41] := BoolToString(fIsVideoCh[3]); {s Video Channel (4)} | |
sPropValues[42] := FloatToStr(fzDistance); {z- Distance} | |
sPropValues[43] := fTravelDuration; {Travel Duration} | |
sPropValues[44] := IntToStr(fFastStackRepeatCount); {Fast Stack Repeat Count} | |
sPropValues[45] := IntToStr(fInitialIntensity); {Initial Intensity} | |
sPropValues[46] := IntToStr(fFinalIntensity); {Final Intensity} | |
sPropValues[47] := FloatToStr(fAtZDistance); {At Z- Distance} | |
sPropValues[48] := IntensityControlToString(fIntensityControl); {Intensity Control} | |
for i := 0 to MAX_CH - 1 do | |
sPropValues[49 + i] := IntToStr(fChMaxPixelValues[i]); | |
ps := nil; pv := nil; | |
try | |
GetMem(ps, FILE_PROP_COUNT * SizeOf(TPropSpec)); | |
GetMem(pv, FILE_PROP_COUNT * SizeOf(TPropVariant)); | |
for i := 0 to FILE_PROP_COUNT - 1 do | |
begin | |
ps^[i].ulKind := PRSPEC_LPWSTR; | |
ps^[i].lpwstr := StringToOLEStr(sPropNames[i]); | |
pv^[i].vt := VT_LPWSTR; | |
pv^[i].pwszVal := StringToOLEStr(sPropValues[i]); | |
end; | |
OleCheck(propertyStorage.WriteMultiple(FILE_PROP_COUNT, @ps[0], @pv[0], 2)); | |
finally | |
if ps <> nil then Freemem(ps); | |
if pv <> nil then Freemem(pv); | |
end; | |
end; | |
//--------------------------- FILE OBJECT: PUBLIC ------------------------------ | |
procedure TMPFile.AddFrameGroup(newFrameGroup: TFrameGroup); | |
begin | |
if FrameCount = 0 then | |
begin | |
{allows overriding frame width and frame height when no frame in file} | |
fFrameHeight := newFrameGroup.frameHeight; | |
fFrameWidth := newFrameGroup.frameWidth; {sets the size of the data array} | |
end; | |
if (fFrameHeight = newFrameGroup.frameHeight) and (fFrameWidth = newFrameGroup.frameWidth) then | |
begin | |
newFrameGroup.FrameIndex := FrameCount; | |
frameGroupList.Add(newFrameGroup); | |
end; | |
end; | |
procedure TMPFile.AverageFrames(chIndex, fromFrame, toFrame: integer; dest: TMPFile); | |
var newFrameGroup: TFrameGroup; | |
avgCount: integer; | |
avgArray: array of integer; | |
i, j: integer; | |
begin | |
avgCount := toFrame - fromFrame + 1; | |
SetLength(avgArray, FrameWidth * FrameHeight); | |
for i := 0 to FrameWidth * FrameHeight - 1 do avgArray[i] := 0; | |
newFrameGroup := TFrameGroup.CreateForOp(dest); | |
newFrameGroup.FrameWidth := FrameWidth; | |
newFrameGroup.FrameHeight := FrameHeight; | |
for j := fromFrame to toFrame do | |
for i := 0 to FrameWidth * FrameHeight - 1 do | |
avgArray[i] := avgArray[i] + Frames[j].channels[chIndex].data[i]; | |
for i := 0 to FrameWidth * FrameHeight - 1 do | |
newFrameGroup.channels[0].data[i] := avgArray[i] div avgCount; | |
dest.AddFrameGroup(newFrameGroup); | |
end; | |
procedure TMPFile.BinaryOp(file1, file2: TMPFile; ch1, ch2, frame1, frame2: integer; gain1, gain2: double; | |
resultFrame: integer); | |
var i, j: integer; | |
dblOpResult: double; | |
iOpResult: int16; | |
frame1Obj, frame2Obj, resultFrameObj: TVideoFrame; | |
begin | |
frame1Obj := file1.Frames[frame1].channels[ch1] as TVideoFrame; | |
frame2Obj := file2.Frames[frame2].channels[ch2] as TVideoFrame; | |
resultFrameObj := Frames[resultFrame].channels[0] as TVideoFrame; | |
for j := 0 to FrameHeight - 1 do | |
for i := 0 to FrameWidth - 1 do | |
begin | |
dblOpResult := gain1 * frame1Obj.Pixels[i, j] + gain2 * frame2Obj.Pixels[i, j]; | |
if dblOpResult > DEFAULT_MAX_PIXEL_VALUE then | |
iOpResult := DEFAULT_MAX_PIXEL_VALUE | |
else if dblOpResult < -DEFAULT_MAX_PIXEL_VALUE - 1 then | |
iOpResult := -DEFAULT_MAX_PIXEL_VALUE - 1 | |
else | |
iOpResult := Round(dblOpResult); | |
resultFrameObj.data[i + j * FrameWidth] := iOpResult; | |
end; | |
OnNewFrames; | |
end; | |
procedure TMPFile.Close(Sender: TObject); | |
var i: integer; | |
begin | |
fbClosing := True; | |
{closes all the windows} | |
if ViewerCount > 0 then | |
for i := 0 to ViewerCount - 1 do | |
Viewers[i].Close; | |
if AnalogWndCount > 0 then | |
for i := 0 to AnalogWndCount - 1 do | |
AnalogWnds[i].Close; | |
Free; | |
end; | |
function TMPFile.CreateEmptyFrame(fromFile: TMPFile): integer; | |
var newFrameGroup: TFrameGroup; | |
begin | |
newFrameGroup := TFrameGroup.CreateForOp(self); | |
newFrameGroup.FrameWidth := fromFile.FrameWidth; | |
newFrameGroup.FrameHeight := fromFile.FrameHeight; | |
AddFrameGroup(newFrameGroup); | |
Result := FrameCount - 1; | |
OnNewFrames; {update each time we project - looks nicer!} | |
end; | |
procedure TMPFile.CopyChannelsToClipboard(bCh2, bCh3: boolean; fromFrame, toFrame: integer); | |
type TCharArray = array[0..Maxint div 2 - 1] of WideChar; | |
var chIndex, rowCount, frameIndex, sampleIndex: integer; | |
timeVal, sampleVal: double; | |
memhandle: THandle; | |
pString: ^TCharArray; | |
swLength, stringindex,maxcharcount: integer; | |
s1: string; | |
sw: array[0..179] of WideChar; | |
begin | |
if not(bCh2 or bCh3) then Exit; | |
if bCh2 then chIndex := 2 else chIndex := 3; | |
rowCount := (toFrame - fromFrame + 1) * ChDataPtsPerFrame[chIndex]; | |
if rowCount <= 65536 then | |
begin | |
Clipboard.Open; | |
Clipboard.Clear; | |
try | |
{fills string with data; 11 digits for each column - each digit is a wide char, 2 columns} | |
{number of rows is (toFrame - fromFrame + 1) * ChDataPtsPerFrame[]} | |
{frameIndex: 0 to toFrame - fromFrame} | |
{time in ms for each frame: (fromFrame + frameIndex) * FrameSize * PixelClock * 1e-6 } | |
{sampleIndex: 0 to ChDataPtsPerFrame[] - 1} | |
{for each sample: sampleIndex * FrameSize * PixelClock * 1e-6 / ChDataPtsPerFrame[]} | |
maxcharcount := SizeOf(WideChar)* ( | |
(2 {columns} * 20 {20 digits} + 3 {Tab, CR, LF}) * rowCount | |
+ 1 {Null} | |
); {wide char} | |
memHandle := GlobalAlloc( | |
GMEM_MOVEABLE or GMEM_DDESHARE or GMEM_ZEROINIT, | |
maxcharcount); | |
if memHandle <> 0 then | |
begin | |
pString := GlobalLock(memHandle); | |
stringindex := 0; | |
for frameIndex := 0 to toFrame - fromFrame do | |
begin | |
ActiveFrameIndex := fromFrame + frameIndex; | |
for sampleIndex := 0 to ChDataPtsPerFrame[chIndex]- 1 do | |
begin | |
timeVal := 1000 * (sampleIndex / ChDataPtsPerFrame[chIndex] + fromFrame + frameIndex) / FrameRate; | |
{timeVal in ms; pixel clock is in increments of 50 ns = 5e-5 ms(20 MHz)} | |
{ timeVal := (FrameSize * PixelClock * 5e-5) * | |
(sampleIndex / ChDataPtsPerFrame[chIndex] + fromFrame + frameIndex);} | |
{sampleVal} | |
sampleVal := ChConvFactor[chIndex] * FullScaleToVal(ChInputRange[chIndex]) * | |
Frames[ActiveFrameIndex].channels[chIndex].data[sampleIndex] / | |
(f_MAX_Y_VALUE + 1) + ChOffset[chIndex]; | |
s1 := Format('%.6f', [timeVal]) + TAB + Format('%g', [sampleVal]) + CRLF; | |
swLength := Length(s1); | |
StringToWideChar(s1, @sw, SizeOf(WideChar) * (swLength + 1)); | |
if stringIndex < maxcharcount div 2 - swLength then | |
begin | |
Move(sw[0], pString^[stringIndex], SizeOf(WideChar) * swLength); | |
stringIndex := stringIndex + swLength; {points to the next character} | |
end; | |
end; | |
end; | |
Clipboard.SetAsHandle(CF_UNICODETEXT, memHandle); | |
end | |
else | |
MessageDlg('Insufficient memory to export data; try saving data to disk as text file.' + CRLF + | |
'(Menu: File\Save\Analog Data As...)', mtError, [mbOK], 0); | |
finally | |
Clipboard.Close; | |
end; | |
end {rowcount <= } | |
else | |
MessageDlg('Too many data samples to export; try saving data to disk as text file.' + CRLF + | |
'(Menu: File\Save\Analog Data As...)', mtError, [mbOK], 0); | |
end; | |
procedure TMPFile.CopyFrames(chIndex, fromFrame, toFrame: integer; dest: TMPFile); {from one file to a memory file, rect to rect} | |
var newFrameGroup: TFrameGroup; | |
i, j: integer; | |
begin | |
for j := fromFrame to toFrame do | |
begin | |
newFrameGroup := TFrameGroup.CreateForOp(dest); | |
newFrameGroup.FrameWidth := FrameWidth; | |
newFrameGroup.FrameHeight := FrameHeight; | |
for i := 0 to FrameWidth * FrameHeight - 1 do | |
newFrameGroup.channels[0].data[i] := Frames[j].channels[chIndex].data[i]; | |
dest.AddFrameGroup(newFrameGroup); | |
end; | |
end; | |
procedure TMPFile.CloneROIs(ROIList: TROIList; fromIndex: integer); {duplicate each ROI but with opposite channel} | |
var i, j, oldCount, chIndex: integer; | |
oldROI, newROI: TSimpleROI; | |
begin | |
with ROIList do | |
if fromIndex <= Count - 1 then | |
begin | |
oldCount := Count; | |
for i := fromIndex to oldCount - 1 do | |
begin | |
oldROI := TSimpleROI(Items[i]); | |
for chIndex := 0 to MAX_CH - 1 do | |
if IsVideoChannel[chIndex] and (oldROI.Channel <> chIndex) then | |
begin | |
if oldROI is TRectangularROI then | |
begin | |
newROI := TRectangularROI.Create; | |
(newROI as TRectangularROI).roiRect := (oldROI as TRectangularROI).roiRect; | |
end | |
else if oldROI is TEllipticalROI then | |
begin | |
newROI := TEllipticalROI.Create; | |
(newROI as TEllipticalROI).roiRect := (oldROI as TEllipticalROI).roiRect; | |
(newROI as TEllipticalROI).FindPixels; | |
end | |
else | |
begin | |
newROI := TObjectROI.Create; | |
if oldROI.PixelCount > 0 then | |
for j := 0 to oldROI.PixelCount - 1 do | |
(newROI as TObjectROI).AddPt(oldROI.Pixels[j]); | |
end; | |
newROI.fChannel := chIndex; | |
newROI.fROIIndex := ROIList.Count + 1; | |
Add(newROI); | |
end; | |
end; | |
end; | |
end; | |
const | |
ALREADY_SCANNED = -32768; | |
procedure TMPFile.DetectROIs(ROIList: TROIList; chIndex, fromFrame, toFrame, threshold, minArea, | |
templateFrom, templateTo: integer); | |
var tempFrameGroup: TFrameGroup; | |
i, j: integer; | |
objectROI: TObjectROI; | |
avgCount: integer; | |
avgArray: array of integer; | |
{nested recursive procedure to find ROI in all adjacent points} | |
procedure FindROIObject(i, j: integer; var aROIObject: TObjectROI); | |
var pixelValue: int16; | |
begin | |
if (i < 0) or (i >= FrameWidth) or (j < 0) or (j >= FrameHeight) then Exit; | |
pixelValue := tempFrameGroup.channels[0].data[j * FrameWidth + i]; | |
if pixelValue >= threshold then | |
begin | |
tempFrameGroup.channels[0].data[j * FrameWidth + i] := ALREADY_SCANNED; | |
if aROIObject = nil then | |
begin | |
aROIObject := TObjectROI.Create; | |
aROIObject.fChannel := chIndex; | |
aROIObject.fROIIndex := ROIList.Count + 1; | |
end; | |
aROIObject.AddPt(Point(i, j)); | |
FindROIObject(i - 1, j - 1, aROIObject); | |
FindROIObject(i , j - 1, aROIObject); | |
FindROIObject(i + 1, j - 1, aROIObject); | |
FindROIObject(i - 1, j , aROIObject); | |
FindROIObject(i + 1, j , aROIObject); | |
FindROIObject(i - 1, j + 1, aROIObject); | |
FindROIObject(i , j + 1, aROIObject); | |
FindROIObject(i + 1, j + 1, aROIObject); | |
end; | |
end; | |
begin | |
// create a temporary frame group | |
tempFrameGroup := TFrameGroup.CreateTempFrameGroup(self); | |
tempFrameGroup.FrameWidth := FrameWidth; | |
tempFrameGroup.FrameHeight := FrameHeight; | |
// average frames from templateFrom to templateTo onto tempFrameGroup | |
avgCount := templateTo - templateFrom + 1; | |
SetLength(avgArray, FrameWidth * FrameHeight); | |
for i := 0 to FrameWidth * FrameHeight - 1 do avgArray[i] := 0; | |
for j := templateFrom to templateTo do | |
for i := 0 to FrameWidth * FrameHeight - 1 do | |
avgArray[i] := avgArray[i] + Frames[j].channels[chIndex].data[i]; | |
for i := 0 to FrameWidth * FrameHeight - 1 do | |
tempFrameGroup.channels[0].data[i] := avgArray[i] div avgCount; | |
// search for objects in tempFrameGroup recursively | |
for j := 0 to FrameHeight - 1 do | |
for i := 0 to FrameWidth - 1 do | |
begin | |
objectROI := nil; | |
FindROIObject(i, j, objectROI); | |
{we found a new object} | |
if objectROI <> nil then | |
ROIList.Add(objectROI); | |
end; | |
// clean up; we eliminate all ObjectROIs that are not large enough | |
if ROIList.Count > 0 then | |
for i := ROIList.Count - 1 downto 0 do | |
if ROIList.ROIs[i] is TObjectROI then | |
if (ROIList.ROIs[i] as TObjectROI).PixelCount < minArea then | |
ROIList.Delete(i); | |
tempFrameGroup.Free; | |
end; | |
function TMPFile.DigitalToAnalog(chIndex, iValue: integer): double; | |
begin | |
Result := ChOffset[chIndex] + ChConvFactor[chIndex] * FullScaleToVal(ChInputRange[chIndex]) * | |
(iValue / (MaxPixelValue + 1)); | |
end; | |
procedure TMPFile.DoBackgroundCorrection; | |
var ch, i, j, pixelIndex: integer; | |
pixelVal, minValue: int16; | |
begin | |
if FrameCount = 0 then Exit; | |
for ch := 0 to MAX_CH - 1 do | |
if VideoChEnabled[ch] then | |
begin | |
minValue := 32767; | |
for i := 0 to FrameWidth - 1 do | |
for j := 0 to FrameHeight - 1 do | |
begin | |
pixelVal := Frames[ActiveFrameIndex].channels[ch].data[i + j * FrameWidth]; | |
if pixelVal < minValue then minValue := pixelVal; | |
end; | |
if minValue < 0 then | |
for i := 0 to FrameWidth - 1 do | |
for j := 0 to FrameHeight - 1 do | |
begin | |
pixelIndex := i + j * FrameWidth; | |
pixelVal := Frames[ActiveFrameIndex].channels[ch].data[pixelIndex]; | |
pixelVal := pixelVal - minValue; | |
Frames[ActiveFrameIndex].channels[ch].data[pixelIndex] := pixelVal; | |
end; | |
end; | |
end; | |
function TMPFile.GetAverage(frameIndex, chIndex: integer; rc: TRect): integer; | |
var i, j: integer; | |
begin | |
Result := 0; | |
for i := rc.Left to rc.Right do | |
for j := rc.Top to rc.Bottom do | |
Result := Result + Frames[frameIndex].channels[chIndex].data[i + j * FrameWidth]; | |
Result := Result div ((rc.Right - rc.Left + 1) * (rc.Bottom - rc.Top + 1)); | |
end; | |
function TMPFile.GetMax(frameIndex, chIndex: integer; rc: TRect; var x, y: integer): integer; | |
var pixelVal, i, j: integer; | |
begin | |
Result := -32768; | |
for i := rc.Left to rc.Right do | |
for j := rc.Top to rc.Bottom do | |
begin | |
pixelVal := Frames[frameIndex].channels[chIndex].data[i + j * FrameWidth]; | |
if pixelVal > Result then | |
begin | |
Result := pixelVal; | |
x := i; | |
y := j; | |
end; | |
end; | |
end; | |
function TMPFile.GetMin(frameIndex, chIndex: integer; rc: TRect; var x, y: integer): integer; | |
var pixelVal, i, j: integer; | |
begin | |
Result := 32768; | |
for i := rc.Left to rc.Right do | |
for j := rc.Top to rc.Bottom do | |
begin | |
pixelVal := Frames[frameIndex].channels[chIndex].data[i + j * FrameWidth]; | |
if pixelVal < Result then | |
begin | |
Result := pixelVal; | |
x := i; | |
y := j; | |
end; | |
end; | |
end; | |
function TMPFile.GetROIAverageValue(ROIList: TROIList; roiIndex, frameIndex: integer): integer; | |
var i, j: integer; | |
theROI: TSimpleROI; | |
roiPixel: TPoint; | |
begin | |
Result := 0; | |
theROI := ROIList.ROIs[roiIndex]; | |
for i := 0 to theROI.PixelCount - 1 do | |
begin | |
roiPixel := theROI.Pixels[i]; | |
j := roiPixel.x + roiPixel.y * FrameWidth; | |
Result := Result + Frames[frameIndex].channels[theROI.Channel].data[j]; | |
end; | |
Result := Result div theROI.PixelCount; | |
end; | |
function TMPFile.GetPixelValue(frameIndex, chIndex, xData, yData: integer): int16; | |
begin | |
Result := 0; | |
if (frameIndex >= 0) and (frameIndex < FrameCount) and IsVideoChannel[chIndex] | |
and (xData >= 0) and (xData < FrameWidth) and (yData >= 0) | |
and (yData < FrameHeight) then | |
Result := Frames[frameIndex].channels[chIndex].data[xData + yData * FrameWidth]; | |
end; | |
function TMPFile.GetPropertyValue(propName: string): string; | |
var ps: TpPropSpecArray; | |
pv: TpPropVariantArray; | |
begin | |
ps := nil; pv := nil; | |
try | |
GetMem(ps, SizeOf(TPropSpec)); | |
GetMem(pv, SizeOf(TPropVariant)); | |
ps^[0].ulKind := PRSPEC_LPWSTR; | |
ps^[0].lpwstr := StringToOLEStr(propName); | |
try | |
OleCheck(propertyStorage.ReadMultiple(1, @ps[0], @pv[0])); | |
Result := WideCharToString(pv^[0].pwszVal); | |
except | |
Result := 'No match'; | |
end; | |
finally | |
if ps <> nil then Freemem(ps); | |
if pv <> nil then Freemem(pv); | |
end; | |
end; | |
function TMPFile.IsOperationOK(chIndex, fromFrame, toFrame: integer; dest: TMPFile): boolean; | |
begin | |
Result := ChEnabled[chIndex] and (fromFrame >= 0) and (fromFrame < FrameCount) and (toFrame >= 0) and | |
(toFrame < FrameCount) and (fromFrame <= toFrame) and dest.IsMemoryFile; | |
end; | |
type EAVIError = class(Exception); | |
TRGBTripleArray = array[0..Maxint div 8] of TRGBTriple; | |
TpRGBTripleArray = ^TRGBTripleArray; | |
procedure TMPFile.MakeAVIMovie(const avifilename: string; chIndex, fromFrame, toFrame, newframeRate: integer; | |
colorScheme: TColorScheme; fromViewer: TObject; bOverlayCh1on2: boolean); | |
var aviFile: IAVIFile; | |
aviStream: IAVIStream; | |
bitmapInfo: TBITMAPINFO; | |
pAviBitmap: TpRGBTripleArray; | |
spCharFileName: array[0..255] of WideChar; | |
spCharStreamName: array[0..63] of WideChar; | |
streamInfo: TAVIStreamInfo; | |
i, j, k, maxPixVal: integer; | |
pixel0, pixel1: TRGBTriple; | |
hr: HResult; | |
const sStreamName = '2-photon laser confocal microscope video stream'; | |
begin | |
maxPixVal := ChMaxPixelValues[chIndex]; {caching value} | |
if AVIFileOpen(aviFile, | |
StringToWideChar(aviFilename, @spCharFileName, 255), | |
OF_CREATE or OF_SHARE_EXCLUSIVE or OF_WRITE, nil) <> 0 then | |
raise EAVIError.Create('Error in creating AVI file'); | |
FillChar(streamInfo, SizeOf(streamInfo), 0); | |
StringToWideChar(sStreamName, @spCharStreamName, 63); | |
with streamInfo do | |
begin | |
fccType := streamtypeVIDEO; | |
fccHandler := 0; | |
dwScale := 1; | |
dwRate := Round(newframeRate); | |
if dwRate > 24 then dwRate := 24; // bound to 24 fps | |
dwSuggestedBufferSize := FrameWidth * FrameHeight; | |
rcFrame := Rect(0, 0, FrameWidth - 1, FrameHeight - 1); | |
for i := 0 to 63 do | |
szName[i] := spCharStreamName[i]; | |
end; | |
if AVIFileCreateStream(aviFile, aviStream, streamInfo) <> 0 then | |
raise EAVIError.Create('Cannot create AVI stream'); | |
FillChar(bitmapInfo, SizeOf(TBITMAPINFO), 0); | |
with bitmapInfo.bmiHeader do | |
begin | |
biSize := SizeOf(TBITMAPINFOHEADER); | |
biWidth := FrameWidth; | |
biHeight := FrameHeight; // we invert bitmap in the loop | |
biPlanes := 1; | |
biBitCount := 24; | |
biCompression := BI_RGB; | |
end; | |
if AVIStreamSetFormat(aviStream, 0, @bitmapInfo, SizeOf(TBITMAPINFOHEADER)) <> 0 then | |
raise EAVIError.Create('Cannot set format of video stream'); | |
GetMem(pAviBitmap, FrameHeight * FrameWidth * SizeOf(TRGBTriple)); | |
i := fromFrame; | |
repeat | |
for j := 0 to FrameHeight * FrameWidth - 1 do | |
begin | |
k := Frames[i].Channels[chIndex].data[j]; | |
if k < 0 then k := 0; | |
k := Muldiv(k, maxPixVal, MAX_FALSE_COLORS - 1); | |
if k > MAX_FALSE_COLORS - 1 then k := MAX_FALSE_COLORS - 1; | |
case colorScheme of | |
CS_GRAYSCALE: pAviBitmap^[j] := Mainform.grayScaleTable[k]; | |
CS_FALSECOLORS: pAviBitmap^[j] := Mainform.falseColorTable[k]; | |
CS_CUSTOMLUT: pAviBitmap^[j] := (fromViewer as TViewerFrm).mpFile.CustomColors[chIndex][k]; | |
end; | |
{Overlay Ch1 on Ch2} | |
if bOverlayCh1on2 and (chIndex = 1) and VideoChEnabled[0] then | |
begin | |
pixel1 := pAviBitmap^[j]; | |
{pixel for Ch1 (index of 0)} | |
k := Frames[i].Channels[0].data[j]; | |
if k < 0 then k := 0; | |
k := Muldiv(k, maxPixVal, MAX_FALSE_COLORS - 1); | |
if k > MAX_FALSE_COLORS - 1 then k := MAX_FALSE_COLORS - 1; | |
case colorScheme of | |
CS_GRAYSCALE: pixel0 := Mainform.grayScaleTable[k]; | |
CS_FALSECOLORS: pixel0 := Mainform.falseColorTable[k]; | |
CS_CUSTOMLUT: pixel0 := (fromViewer as TViewerFrm).mpFile.CustomColors[0][k]; | |
end; | |
pixel1.rgbtBlue := pixel1.rgbtBlue or pixel0.rgbtBlue; | |
pixel1.rgbtGreen := pixel1.rgbtGreen or pixel0.rgbtGreen; | |
pixel1.rgbtRed := pixel1.rgbtRed or pixel0.rgbtRed; | |
pAviBitmap^[j] := pixel1; | |
end; | |
end; | |
hr := AVIStreamWrite(aviStream, i - fromFrame, 1, pAviBitmap, | |
FrameWidth * FrameHeight * SizeOf(TRGBTriple), AVIIF_KEYFRAME, nil, nil); | |
i := i + 1; | |
until not Succeeded(hr) or (i > toFrame); | |
Freemem(pAviBitmap, FrameHeight * FrameWidth * SizeOf(TRGBTriple) ); | |
{instead of using the AVI API functions to release the stream and file, | |
we do it the Delphi way by making them nil} | |
aviStream := nil; | |
aviFile := nil; | |
if not Succeeded(hr) then | |
raise EAVIError.Create('Error writing frame to file'); | |
end; | |
function TMPFile.MakeTIFF(const avifilename: string; chIndex, fromFrame, toFrame: integer): boolean; | |
var Stream : TFileStream; | |
i, j, k, l, sLength, maxPixVal: integer; | |
pixelValue: int16; | |
wPixelValues: array of Word; | |
videoFrame: TFrame; | |
ifd: TIFD; | |
sImageDescription: string; | |
begin | |
Result := True; | |
maxPixVal := ChMaxPixelValues[chIndex]; {just caching this value} | |
Stream := TFileStream.Create(avifilename, fmCreate Or fmShareExclusive); | |
try | |
sImageDescription := Format(sTIFFPropNames, [ | |
chIndex + 1, | |
Resolution, | |
ScanModeToString(ScanMode), | |
XStagePosition, | |
YStagePosition, | |
ZStagePosition, | |
StackFrameCount, | |
StackInterval, | |
StackAveragingCount, | |
StackRepeatCount, | |
Magnification, | |
Rotation, | |
XFrameOffset, | |
YFrameOffset, | |
FrameRate ]); | |
{Write TIFF file header} | |
Stream.Write(tiffHeader, SizeOf(tiffHeader)); | |
{Write the IFDs} | |
MakeIFD(ifd); | |
sLength := Length(sImageDescription) + 1; {includes the NULL finishing the string} | |
with ifd do | |
begin | |
tagRecords[22].Count := sLength; | |
tagRecords[2].dataOffset := FrameWidth; | |
tagRecords[3].dataOffset := FrameHeight; | |
tagRecords[12].dataOffset := FrameHeight; {RowsPerStrip} | |
tagRecords[13].dataOffset := FrameHeight * FrameWidth * SizeOf(Word); {StripByteCounts} | |
end; | |
for i := fromFrame to toFrame do | |
with ifd do | |
begin | |
{XResolution} | |
ifd.tagRecords[16].dataOffset := SizeOf(tiffHeader) + (i - fromFrame + 1) * (SizeOf(ifd) + sLength) | |
- 4 * SizeOf(integer) - sLength; | |
{YResolution} | |
ifd.tagRecords[17].dataOffset := SizeOf(tiffHeader) + (i - fromFrame + 1) * (SizeOf(ifd) + sLength) | |
- 2 * SizeOf(integer) - sLength; | |
{ImageDescription} | |
ifd.tagRecords[22].dataOffset := SizeOf(tiffHeader) + (i - fromFrame + 1) * (SizeOf(ifd) + sLength) | |
- sLength; | |
{StripOffsets} | |
ifd.tagRecords[9].dataOffset := SizeOf(tiffHeader) + (toFrame - fromFrame + 1) * (SizeOf(ifd) + sLength) + | |
FrameWidth * FrameHeight * SizeOf(Word) * (i - fromFrame); | |
if i <> toFrame then | |
nextIDFoffset := SizeOf(tiffHeader) + (i - fromFrame + 1) * (SizeOf(ifd) + sLength) | |
else | |
nextIDFoffset := 0; | |
Stream.Write(ifd, SizeOf(ifd)); | |
{Write the description string} | |
Stream.Write(sImageDescription[1], sLength); | |
end; | |
{Write frame data for each frame} | |
SetLength(wPixelValues, FrameHeight * FrameWidth); | |
for i := fromFrame to toFrame do | |
begin | |
videoFrame := Frames[i].Channels[chIndex]; | |
for j := 0 to FrameHeight - 1 do | |
begin | |
for k := 0 to FrameWidth - 1 do | |
begin | |
l := j * FrameWidth + k; | |
pixelValue := videoFrame.data[l]; | |
{truncate value and normalize to 0..65535} | |
if pixelValue < 0 then | |
begin | |
wPixelValues[l] := 0; | |
Result := False; | |
end | |
else | |
wPixelValues[l] := Muldiv(pixelValue, 65535, maxPixVal); | |
end; | |
end; | |
Stream.Write(wPixelValues[0], FrameHeight * FrameWidth * SizeOf(Word)); | |
end; | |
finally | |
Stream.Free; | |
end; | |
end; | |
procedure TMPFile.NewAnalogWnd; | |
var analogFrm: TAnalogFrm; | |
begin | |
analogFrm := TAnalogFrm.Create(Mainform); | |
analogFrm.Initialize(self); | |
analogFrm.Show; | |
analogWndList.Add(analogFrm); | |
analogFrm.FormResize(nil); {forces painting} | |
end; | |
procedure TMPFile.NewViewer; | |
var viewerFrm: TViewerFrm; | |
begin | |
viewerFrm := TViewerFrm.Create(Mainform); | |
viewerFrm.Initialize(self, viewerList.Add(viewerFrm) + 1); | |
viewerFrm.CurrentFrameIndex := 0; | |
viewerFrm.Show; | |
end; | |
procedure TMPFile.OnNewFrames; | |
var i: integer; | |
begin | |
if FrameCount <= 0 then Exit; | |
if viewerList.Count > 0 then | |
for i := 0 to viewerList.Count - 1 do | |
TViewerFrm(viewerList.Items[i]).CurrentFrameIndex := FrameCount - 1; | |
end; | |
procedure TMPFile.OnWndClose(wnd: TForm); {when a viewer or analog wnd closes} | |
var i: integer; | |
begin | |
if not Closing and not Mainform.bAppClosing then | |
if AnalogWndCount + ViewerCount = 1 then | |
{the last window standing for this file: if we close, file object is free} | |
Free | |
else | |
begin | |
if analogWndList <> nil then | |
begin | |
i := analogWndList.IndexOf(wnd); | |
if i >= 0 then analogWndList.Remove(wnd); | |
end; | |
i := viewerList.IndexOf(wnd); | |
if i >= 0 then viewerList.Remove(wnd); | |
end; | |
end; | |
procedure TMPFile.SaveChannelsToFile(bASCII: boolean; fname: string; bCh2, bCh3: boolean; fromFrame, toFrame: integer); | |
var chIndex, frameIndex, sampleIndex: integer; | |
timeVal, sampleVal: double; | |
fileStream: TFileStream; | |
swLength: integer; | |
s1: string; | |
sw: array[0..179] of WideChar; | |
begin | |
if not(bCh2 or bCh3) then Exit; | |
if bCh2 then chIndex := 2 else chIndex := 3; | |
fileStream := TFileStream.Create(fname, fmCreate or fmShareExclusive); | |
try | |
fileStream.Seek(0, soFromBeginning); | |
{fills string with data; 11 digits for each column - each digit is a wide char, 2 columns} | |
{number of rows is (toFrame - fromFrame + 1) * ChDataPtsPerFrame[]} | |
{frameIndex: 0 to toFrame - fromFrame} | |
{time in ms for each frame: (fromFrame + frameIndex) * FrameSize * PixelClock * 1e-6 } | |
{sampleIndex: 0 to ChDataPtsPerFrame[] - 1} | |
{for each sample: sampleIndex * FrameSize * PixelClock * 1e-6 / ChDataPtsPerFrame[]} | |
for frameIndex := 0 to toFrame - fromFrame do | |
begin | |
ActiveFrameIndex := fromFrame + frameIndex; | |
for sampleIndex := 0 to ChDataPtsPerFrame[chIndex]- 1 do | |
begin | |
timeVal := (sampleIndex / ChDataPtsPerFrame[chIndex] + fromFrame + frameIndex) / FrameRate; | |
{timeVal in s; pixel clock is in increments of 50 ns = 5e-5 ms(20 MHz)} | |
{ timeVal := (FrameSize * PixelClock * 5e-5) * | |
(sampleIndex / ChDataPtsPerFrame[chIndex] + fromFrame + frameIndex);} | |
{sampleVal} | |
sampleVal := ChConvFactor[chIndex] * FullScaleToVal(ChInputRange[chIndex]) * | |
Frames[ActiveFrameIndex].channels[chIndex].data[sampleIndex] / | |
(f_MAX_Y_VALUE + 1) + ChOffset[chIndex]; | |
s1 := Format('%.6f', [timeVal]) + TAB + Format('%g', [sampleVal]) + CRLF; | |
if bASCII then | |
fileStream.Write(s1[1], Length(s1)) | |
else | |
begin | |
swLength := 2 * Length(s1); {Unicode business} | |
StringToWideChar(s1, @sw, swLength + 1); | |
fileStream.Write(sw, swLength); | |
end; | |
end; | |
end; | |
finally | |
fileStream.Free; | |
end; | |
end; | |
procedure TMPFile.StackX(chIndex, fromFrame, toFrame, fromY, toY: integer; dest: TMPFile);{creates new frame} | |
var newFrameGroup: TFrameGroup; | |
i, j, k: integer; | |
value: int16; | |
pDataElt: ^int16; | |
begin | |
newFrameGroup := TFrameGroup.CreateForOp(dest); | |
newFrameGroup.FrameWidth := FrameWidth; | |
newFrameGroup.FrameHeight := toFrame - fromFrame + 1; | |
dest.AddFrameGroup(newFrameGroup); | |
for i := fromFrame to toFrame do | |
begin | |
ActiveFrameIndex := i; | |
for j := 0 to FrameWidth - 1 do | |
begin | |
pDataElt := @(newFrameGroup.Channels[0].data[(i - fromFrame) * FrameWidth + j]); | |
pDataElt^ := 0; | |
for k := fromY to toY do | |
begin | |
value := Frames[ActiveFrameIndex].channels[chIndex].data[k * FrameWidth + j]; | |
if value > DEFAULT_MAX_PIXEL_VALUE then value := DEFAULT_MAX_PIXEL_VALUE; | |
if value > pDataElt^ then pDataElt^ := value; | |
end; | |
end; | |
dest.OnNewFrames; {update each time we project - looks nicer!} | |
end; | |
end; | |
function TMPFile.SizeOfFrameCompatible(width, height: integer): boolean; | |
begin | |
if FrameCount = 0 then | |
Result := True | |
else | |
if (width = FrameWidth) and (height = FrameHeight) then | |
Result := True | |
else | |
begin | |
MessageDlg( 'Operation not possible.' + CRLF + | |
'Destination workspace has different frame size.', | |
mtError, [mbOK], 0); | |
Result := False; | |
end; | |
end; | |
procedure TMPFile.StackY(chIndex, fromFrame, toFrame, fromX, toX: integer; dest: TMPFile); | |
var newFrameGroup: TFrameGroup; | |
i, j, k: integer; | |
value: int16; | |
pDataElt: ^int16; | |
begin | |
newFrameGroup := TFrameGroup.CreateForOp(dest); | |
newFrameGroup.FrameWidth := FrameHeight; | |
newFrameGroup.FrameHeight := toFrame - fromFrame + 1; | |
dest.AddFrameGroup(newFrameGroup); | |
for i := fromFrame to toFrame do | |
begin | |
ActiveFrameIndex := i; | |
for j := 0 to FrameHeight - 1 do | |
begin | |
pDataElt := @newFrameGroup.Channels[0].data[(i - fromFrame) * FrameHeight + j]; | |
pDataElt^ := 0; | |
for k := fromX to toX do | |
begin | |
value := Frames[ActiveFrameIndex].channels[chIndex].data[j * FrameWidth + k]; | |
if value > DEFAULT_MAX_PIXEL_VALUE then value := DEFAULT_MAX_PIXEL_VALUE; | |
if value > pDataElt^ then pDataElt^ := value; | |
end; | |
end; | |
dest.OnNewFrames; {update each time we project - looks nicer!} | |
end; | |
end; | |
procedure TMPFile.StackZ(chIndex, fromFrame, toFrame: integer; dest: TMPFile); | |
var newFrameGroup: TFrameGroup; | |
i, j, k: integer; | |
value: int16; | |
pDataElt: ^int16; | |
begin | |
newFrameGroup := TFrameGroup.CreateForOp(dest); | |
newFrameGroup.FrameWidth := FrameWidth; | |
newFrameGroup.FrameHeight := FrameHeight; | |
for i := 0 to FrameWidth * FrameHeight - 1 do | |
newFrameGroup.Channels[0].data[i] := 0; | |
dest.AddFrameGroup(newFrameGroup); | |
for i := fromFrame to toFrame do | |
begin | |
ActiveFrameIndex := i; | |
for j := 0 to FrameHeight - 1 do | |
for k := 0 to FrameWidth - 1 do | |
begin | |
pDataElt := @newFrameGroup.Channels[0].data[j * FrameWidth + k]; | |
value := Frames[ActiveFrameIndex].channels[chIndex].data[j * FrameWidth + k]; | |
if value > DEFAULT_MAX_PIXEL_VALUE then value := DEFAULT_MAX_PIXEL_VALUE; | |
if value > pDataElt^ then pDataElt^ := value; | |
end; | |
dest.OnNewFrames; {update each time we project - looks nicer!} | |
end; | |
end; | |
function TMPFile.SaveAs(const sFilename: string): TFileErr; | |
var hr: HResult; | |
i: integer; | |
begin | |
// create the file on disk | |
hr := StgCreateDocFile(StringToOLEStr(sFilename), OFLAGS, 0, rootStorage); | |
if Succeeded(hr) then | |
begin | |
propertySetStorage := rootStorage as IPropertySetStorage; | |
propertySetStorage.Create(FMTID_User_Defined_Properties, | |
FMTID_User_Defined_Properties, PROPSETFLAG_DEFAULT, OFLAGS, propertyStorage); | |
rootStorage.SetClass(GUID_MPD); | |
// save user information | |
WritePropertySet; | |
frameCommentList.SaveFrameComments; | |
// change status of file and filename | |
fFilename := sFilename; | |
fbIsMemoryFile := False; | |
fFrameCount := frameGroupList.Count; | |
// opens the channels | |
OLECheck(rootStorage.CreateStream('Ch0', OFLAGS, 0, 0, chStreams[0])); | |
// save the frame list | |
for i := 0 to frameGroupList.Count - 1 do | |
(TFrameGroup(frameGroupList.Items[i]).channels[0] as TVideoFrame).SaveToFile; | |
// create the current frame group (at frame Index 0) | |
fActiveFrameIndex := 0; | |
fCurrentFrameGroup := TFrameGroup(frameGroupList.Items[0]); | |
// destroys the frame list (except first frame at index 0) | |
if frameGroupList.Count> 1 then | |
for i := 1 to frameGroupList.Count - 1 do | |
TFrameGroup(frameGroupList.Items[i]).Free; | |
frameGroupList.Free; | |
frameGroupList := nil; | |
Result := feOK; | |
// notify all the viewers as the name change | |
if viewerList.Count > 0 then | |
for i := 0 to viewerList.Count - 1 do | |
TForm(viewerList.Items[i]).Caption := 'Video Channels - ' + | |
ExtractFileName(fFilename); | |
end | |
else | |
Result := StgErrToFileErr(hr); | |
end; | |
procedure TMPFile.SubtractFrame(chIndex, plusFrameIndex, minusFrameIndex: integer; dest: TMPFile); | |
var newFrameGroup: TFrameGroup; | |
i: integer; | |
value, minValue: int16; | |
begin | |
newFrameGroup := TFrameGroup.CreateForOp(dest); | |
newFrameGroup.FrameWidth := FrameWidth; | |
newFrameGroup.FrameHeight := FrameHeight; | |
for i := 0 to FrameWidth * FrameHeight - 1 do | |
newFrameGroup.channels[0].data[i] := Frames[plusFrameIndex].channels[chIndex].data[i]; | |
minValue := DEFAULT_MAX_PIXEL_VALUE; | |
for i := 0 to FrameWidth * FrameHeight - 1 do | |
begin | |
value := newFrameGroup.channels[0].data[i] - Frames[minusFrameIndex].channels[chIndex].data[i]; | |
if value < minValue then minValue := value; | |
if value > DEFAULT_MAX_PIXEL_VALUE then value := DEFAULT_MAX_PIXEL_VALUE; | |
newFrameGroup.channels[0].data[i] := value; | |
end; | |
{bring minimal pixel level to 0} | |
if minValue < 0 then | |
for i := 0 to FrameWidth * FrameHeight - 1 do | |
begin | |
value := newFrameGroup.channels[0].data[i] - minValue; | |
if value > DEFAULT_MAX_PIXEL_VALUE then value := DEFAULT_MAX_PIXEL_VALUE; | |
newFrameGroup.channels[0].data[i] := value; | |
end; | |
dest.AddFrameGroup(newFrameGroup); | |
end; | |
constructor TMPFile.CreateFromTemplate(const sFilename: string; templateFile: TMPFile); | |
var i: integer; | |
begin | |
{a worskpace file has always one video channel and no analog channel} | |
fResolution := templateFile.fResolution; | |
fActiveFrameIndex := -1; | |
fAngle := templateFile.Angle; | |
fbIsMemoryFile := True; | |
fChEnabled[0] := True; | |
fChEnabled[1] := False; | |
fChEnabled[2] := False; | |
fChEnabled[3] := False; | |
for i := 0 to MAX_CH - 1 do | |
begin | |
fChConvFactors[i] := templateFile.ChConvFactor[i]; | |
fChDataPtsPerFrames[i] := templateFile.ChDataPtsPerFrame[i]; | |
fChInputRanges[i] := templateFile.ChInputRange[i]; | |
fChNames[i] := templateFile.ChNames[i]; | |
fChPrefixes[i] := templateFile.ChPrefix[i]; | |
fChUnits[i] := templateFile.ChUnit[i]; | |
fChOffsets[i] := templateFile.ChOffset[i]; | |
fIsVideoCh[i] := False; | |
fChMaxPixelValues[i] := templateFile.ChMaxPixelValues[i]; | |
end; | |
fFilename := sFilename; | |
fFrameCount := 0; | |
fFrameHeight := templateFile.FrameHeight; | |
fFrameWidth := templateFile.FrameWidth; | |
fLineRepeatCount := templateFile.LineRepeatCount; | |
fMagnification := templateFile.Magnification; | |
fPixelClock := templateFile.PixelClock; | |
fRotation := templateFile.Rotation; | |
fScanMode := SM_MOVIE; {a workspace is always a movie} | |
fStackAveragingCount := templateFile.LineRepeatCount; | |
fStackFrameCount := templateFile.StackFrameCount; | |
fStackInterval := templateFile.StackInterval; | |
fStackRepeatCount := templateFile.StackRepeatCount; | |
fXFrameOffset := templateFile.XFrameOffset; | |
fXStagePosition := templateFile.XStagePosition; | |
fYFrameOffset := templateFile.YFrameOffset; | |
fYStagePosition := templateFile.YStagePosition; | |
fZStagePosition := templateFile.ZStagePosition; | |
{color information here} | |
baseColors := templateFile.baseColors; | |
negativeColors := templateFile.negativeColors; | |
midRangeColors := templateFile.midRangeColors; | |
maxColors := templateFile.maxColors; | |
MaxPixels := templateFile.MaxPixels; | |
frameCommentList := TFrameCommentList.Create(self); | |
frameGroupList := TList.Create; | |
bDirty := False; | |
viewerList := TList.Create; | |
NewViewer; | |
end; | |
constructor TMPFile.CreateFromFile(const sFilename: string); | |
var i: integer; | |
hr: HResult; | |
begin | |
{opens the storage} | |
InitializeColors; | |
hr := StgOpenStorage(StringToOLEStr(sFilename), nil, RFLAGS, nil, 0, rootStorage); | |
if Succeeded(hr) then | |
begin | |
propertySetStorage := rootStorage as IPropertySetStorage; | |
if not Succeeded(propertySetStorage.Open(FMTID_User_Defined_Properties, | |
RFLAGS, propertyStorage)) then MessageDlg('Cannot open property set', mtError, [mbOK], 0); | |
ReadPropertySet; | |
for i := 0 to MAX_CH - 1 do | |
if chEnabled[i] then | |
rootStorage.OpenStream(StringToOleStr('Ch' + IntToStr(i)), nil, RFLAGS, | |
0, chStreams[i]); | |
AdjustFrameCount; | |
fFilename := sFilename; | |
if ScanMode = SM_REGIONSCAN then GetRegions; | |
fCurrentFrameGroup := TFrameGroup.Create(self); | |
fActiveFrameIndex := -1; ActiveFrameIndex := 0; {forces loading} | |
frameCommentList := TFrameCommentList.Create(self); | |
frameCommentList.LoadFrameComments; | |
viewerList := TList.Create; | |
NewViewer; | |
if (AnalogChCount > 0) and (ScanMode <> SM_STACK) and (ScanMode <> SM_FASTSTACK) then | |
{just to be on the safe side, if the analog streams are empty, we bail} | |
if (chStreams[2] <> nil) or (chStreams[3] <> nil) then | |
begin | |
analogWndList := TList.Create; | |
NewAnalogWnd; | |
end; | |
end | |
else | |
MessageDlg(FileErrToStr(StgErrToFileErr(hr)), mtError, [mbOK], 0); | |
end; | |
destructor TMPFile.Destroy; | |
var i: integer; | |
begin | |
fCurrentFrameGroup.Free; | |
frameGroupList.Free; | |
if analogWndList <> nil then | |
begin | |
if analogWndList.Count > 0 then | |
for i := 0 to analogWndList.Count - 1 do | |
begin | |
TAnalogFrm(analogWndList.Items[i]).mpFile := nil; | |
TAnalogFrm(analogWndList.Items[i]).Close; | |
if Mainform.bAppClosing then Application.ProcessMessages; | |
end; | |
analogWndList.Free; | |
end; | |
{a lot of Windows voodoo here - why it seems to work beats me} | |
if viewerList.Count > 0 then | |
for i := 0 to viewerList.Count - 1 do | |
begin | |
TViewerFrm(viewerList.Items[i]).mpFile := nil; | |
TViewerFrm(viewerList.Items[i]).Close; | |
if Mainform.bAppClosing then Application.ProcessMessages; | |
end; | |
viewerList.Free; | |
frameCommentList.Free; | |
{ for i := 0 to MAX_CH - 1 do channels[i] := nil;} | |
propertyStorage := nil; | |
propertySetStorage := nil; | |
rootStorage := nil; | |
Mainform.FileList.NotifyFileClosing(self); | |
end; | |
{********************************* TFileList **********************************} | |
{------------------------------- TFileList: private ---------------------------} | |
function TFileList.IsMPFile(const sFilename: string): boolean; | |
{var clsid: TCLSID;} | |
begin | |
{ Result := False;} | |
{if Succeeded(StgIsStorageFile(StringToOLEStr(sFilename)) then} | |
{ if Succeeded(GetClassFile(StringToOLEStr(sFilename), clsid)) then | |
Result := IsEqualGUID(clsid, GUID_MPD);} | |
Result := True; | |
end; | |
function TFileList.GetTemporaryFileName: string; | |
var i: integer; | |
begin | |
i := 1; | |
Result := 'Workspace ' + IntToStr(i); | |
while IndexOf(Result) >= 0 do | |
begin | |
i := i + 1; | |
Result := 'Workspace ' + IntToStr(i); | |
end; | |
end; | |
function TFileList.Load(const sFilename: string): TFileErr; | |
begin | |
if not IsMPFile(sFilename) then | |
Result := feNotAMPFile | |
else if IndexOf(sFilename) >= 0 then | |
Result := feFileAlreadyOpen | |
else | |
begin | |
AddObject(sFilename, TMPFile.CreateFromFile(sFilename)); | |
Result := feOK; | |
end; | |
end; | |
{------------------------------- TFileList: public ---------------------------} | |
procedure TFileList.FillComboBoxWithWorkspaces(aComboBox: TComboBox); | |
var i: integer; | |
begin | |
aComboBox.Clear; | |
if Count > 0 then | |
begin | |
for i := 0 to Count - 1 do | |
if TMPFile(Objects[i]).IsMemoryFile then | |
aComboBox.Items.AddObject(TMPFile(Objects[i]).Filename, Objects[i]); | |
if aComboBox.Items.Count > 0 then aComboBox.ItemIndex := 0; | |
end; | |
end; | |
procedure TFileList.NewFile(templateFile: TMPFile); | |
var tempFileName: string; | |
begin | |
tempFileName := GetTemporaryFileName; | |
AddObject(tempFileName, TMPFile.CreateFromTemplate(tempFileName, templateFile)); | |
end; | |
procedure TFileList.NotifyFileClosing(Sender: TMPFile); | |
var i: integer; | |
begin | |
if not Mainform.bAppClosing then | |
begin | |
i := IndexOfObject(Sender); | |
if i >= 0 then Delete(i); | |
end; | |
end; | |
function TFileList.WorkspaceCount: integer; | |
var i: integer; | |
begin | |
Result := 0; | |
if Count > 0 then | |
for i := 0 to Count - 1 do | |
if TMPFile(Objects[i]).IsMemoryFile then Result := Result + 1; | |
end; | |
procedure TFileList.SaveFileAs(mpFile: TMPFile; const newName: string); | |
var i: integer; | |
fe: TFileErr; | |
begin | |
i := IndexOfObject(mpFile); | |
if i >= 0 then | |
if TMPFile(Objects[i]).IsMemoryFile then | |
begin | |
fe := TMPFile(Objects[i]).SaveAs(newName); | |
if fe = feOK then | |
{swaps names} | |
Strings[i] := newName | |
else | |
MessageDlg('Cannot save ' + Strings[i] + ' as' + CRLF + | |
newName + CRLF + | |
FileErrToStr(fe), mtError, [mbOK], 0); | |
end; | |
end; | |
procedure TFileList.Open(const sFilename: string); | |
var fe: TFileErr; | |
begin | |
if IndexOf(sFilename) >= 0 then | |
MessageDlg(Format(sAlreadyLoaded, [sFilename]), mtInformation, [mbOK], 0) | |
else | |
begin | |
fe := Load(sFilename); | |
if fe <> feOK then | |
MessageDlg(FileErrToStr(fe), mtError, [mbOK], 0) | |
else | |
dataDirectory := ExtractFilePath(sFilename); | |
end; | |
end; | |
destructor TFileList.Destroy; | |
var i: integer; | |
begin | |
if Count > 0 then | |
for i := 0 to Count - 1 do | |
TMPFile(Objects[i]).Free; | |
inherited Destroy; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit MPUnit; | |
interface | |
uses Forms, Registry, Graphics, Windows, SysUtils, Classes, Messages, StdCtrls, ActiveX, | |
ComObj; | |
const | |
MAX_CH = 4; {4 AI channels in National Instruments PCI-6110E} | |
DEFAULT_DEVICE_INDEX = 3; {PCI-6110E multifunction board index} | |
DEFAULT_SHUTTER_DEVICE_INDEX = 2; {PCI-6711 I/O board controlling the shutter} | |
BASE_CLOCK = 5e-8; {50 ns base clock = 20 MHz clock frequency} | |
PCI_6110E = 241; {code for the PCI-6110E} | |
PCI_6711_1 = 261; // channel one | |
PCI_6711_2 = 262; //channel two | |
PCI_6711_3 = 263; // channel three | |
PCI_6711_4 = 264; // channel four | |
{the GUID for multiphoton data files} | |
GUID_MPD: TGUID = '{5BC02769-74F0-47DF-929E-2E5D3630D9B5}'; | |
CR = Chr(10) {+ Chr(13)}; | |
TAB = Chr(9); | |
type | |
int16 = Smallint; | |
int32 = Integer; | |
TWaveformArray = array[0..1,0..MaxInt div 8] of int16; | |
TpWaveform = ^TWaveformArray; | |
TDigitalWaveform = array[0..MaxInt div 4] of int16; | |
TpDigitalWaveform = ^TDigitalWaveform; | |
TFrameData = array[0..MaxInt div 4] of int16; | |
TpFrameData = ^TFrameData; | |
TPrecision = (PREC_8_BIT, PREC_10_BIT, PREC_12_BIT, PREC_14_BIT, PREC_16_BIT); | |
TDisplayMode = (DM_RECORDING, DM_ANALYZING); | |
TTimeValue = int64; {all times in ns} | |
TFullScaleVal = (pm_42V, pm_20V, pm_10V, pm_5V, pm_2V, pm_1V, pm_0_5V, pm_0_2V); | |
TInputRange = Set Of TFullScaleVal; | |
TPrefix = ( tpXENNO, tpYOCTO, tpZEPTO, tpATTO, tpFEMTO, tpPICO, tpNANO, | |
tpMICRO, tpMILLI, tpUNITY, tpKILO, tpMEGA, tpGIGA, tpTERA, tpPETA, | |
tpECTA, tpZETTA, tpYOTTA, tpXENNA, tpZERO, tpNONE ); | |
TPhysVal = record | |
value: double; | |
prefix: integer; {index in the StringList of prefix} | |
end; | |
TPhysValue = record | |
value: double; | |
defaultPrefix: TPrefix; | |
physUnit: string[15]; | |
end; | |
TTimeVal = record | |
value: double; | |
prefix: integer; {index in the StringList of prefix} | |
end; | |
TScanMode = (SM_MOVIE, SM_STACK, SM_STACKMOVIE, SM_LINESCAN, SM_REPEAT_LINESCAN); | |
TStopScanMode = (SSM_OK, SSM_USER, SSM_FRAME_COUNT_REACHED, SSM_DATAOVERRUN, SSM_DISKERROR); | |
TStopStimMode = (SSTM_USER, SSTM_SCAN_STOPPED); | |
TConfigRecord = record | |
scanMode: TScanMode; | |
stackCount, | |
XFrameOffset, | |
YFrameOffset, | |
FrameWidth, | |
FrameHeight, | |
PixelClock: integer; | |
zInterval : double; | |
ChConvFactors: array[0..MAX_CH -1] of double; | |
ChDataPtsPerFrames: array[0..MAX_CH -1] of integer; | |
ChEnabled: array[0..MAX_CH - 1] of boolean; | |
ChInputRanges: array[0..MAX_CH - 1] of TFullScaleVal; | |
ChNames: array[0..MAX_CH - 1] of string[32]; | |
ChOffsets: array[0..MAX_CH -1] of double; | |
ChPrefixes: array[0..MAX_CH -1] of TPrefix; | |
ChUnits: array[0..MAX_CH - 1] of string[32]; | |
end; | |
TConfiguration = class | |
private | |
bDirty: boolean; | |
sConfigName: string; | |
fXFrameOffset, | |
fYFrameOffset, | |
fFrameWidth, | |
fFrameHeight, | |
fPixelClock {in increments of 50 ns (= 20 MHz)}: integer; | |
fScanMode: TScanMode; | |
fChConvFactors: array[0..MAX_CH -1] of double; | |
fChDataPtsPerFrames: array[0..MAX_CH -1] of integer; | |
fChEnabled: array[0..MAX_CH - 1] of boolean; | |
fChInputRanges: array[0..MAX_CH - 1] of TFullScaleVal; | |
fChNames: array[0..MAX_CH - 1] of string; | |
fChOffsets: array[0..MAX_CH -1] of double; | |
fChPrefixes: array[0..MAX_CH -1] of TPrefix; | |
fChUnits: array[0..MAX_CH - 1] of string; | |
procedure DefaultConfig; | |
function GetAnalogChCount: integer; | |
function GetFrameRate: double; | |
function GetChAnalogFreqs(chIndex: integer): double; | |
function GetChConvFactors(chIndex: integer): double; | |
function GetChCount: integer; | |
function GetChDataPtsPerFrames(chIndex: integer): integer; | |
function GetChEnabled(chIndex: integer): boolean; | |
function GetChInputRanges(chIndex: integer): TFullScaleVal; | |
function GetChNames(chIndex: integer): string; | |
function GetChOffsets(chIndex: integer): double; | |
function GetChPrefixes(chIndex: integer): TPrefix; | |
function GetChUnits(chIndex: integer): string; | |
function GetFullFrameWidth: integer; | |
function GetVideoChCount: integer; | |
procedure SetChConvFactors(chIndex: integer; newconvfactor: double); | |
procedure SetChDataPtsPerFrames(chIndex: integer; newDataPtsPerFrames: integer); | |
procedure SetChEnabled(chIndex: integer; newChEnabled: boolean); | |
procedure SetChInputRanges(chIndex: integer; newChInputRanges: TFullScaleVal); | |
procedure SetChNames(chIndex: integer; newChNames: string); | |
procedure SetChOffsets(chIndex: integer; newChOffsets: double); | |
procedure SetChPrefixes(chIndex: integer; newChPrefixes: TPrefix); | |
procedure SetChUnits(chIndex: integer; newChUnits: string); | |
procedure SetFrameHeight(newHeight: integer); | |
procedure SetFrameRate(newRate: double); | |
procedure SetFrameWidth(newWidth: integer); | |
procedure SetPixelClock(newClockRate: integer); | |
procedure SetScanMode(newMode: TScanMode); | |
procedure SetXFrameOffset(newXOffset: integer); | |
procedure SetYFrameOffset(newYOffset: integer); | |
public | |
stackCount: integer; | |
zInterval: double; | |
function AnalogToDigitalValue(chIndex: integer; analogVal: double): integer; | |
procedure CopyTo(var configRecord: TConfigRecord); | |
function DigitalToAnalogValue(chIndex: integer; digitalVal: integer): double; | |
procedure GetMaxFrameRate(iframeWidth, iFrameHeight: integer; var newFrameRate: double; | |
var newPixelRate: integer); | |
procedure OpenConfiguration(const fname: string); | |
procedure RestoreFrom(const configRecord: TConfigRecord); | |
procedure SaveConfiguration(const fname: string); | |
function PixelRateToFrameRate(newPixelRate, iframeWidth, iframeHeight: integer; var newFrameRate: double): boolean; | |
function FrameRateToPixelRate(newFrameRate: double; iframeWidth, iframeHeight: integer; var newPixelRate: integer): boolean; | |
constructor Create; | |
property AnalogChCount: integer read GetAnalogChCount; | |
property ChAnalogFreqs[chIndex: integer]: double read GetChAnalogFreqs; | |
property ChConvFactors[chIndex: integer]: double read GetChConvFactors write SetChConvFactors; | |
property ChCount: integer read GetChCount; | |
property ChDataPtsPerFrames[chIndex: integer]: integer read GetChDataPtsPerFrames write SetChDataPtsPerFrames; | |
property ChEnabled[chIndex: integer]: boolean read GetChEnabled write SetChEnabled; | |
property ChInputRanges[chIndex: integer]: TFullScaleVal read GetChInputRanges write SetChInputRanges; | |
property ChNames[chIndex: integer]: string read GetChNames write SetChNames; | |
property ChOffsets[chIndex: integer]: double read GetChOffsets write SetChOffsets; | |
property ChPrefixes[chIndex: integer]: TPrefix read GetChPrefixes write SetChPrefixes; | |
property ChUnits[chIndex: integer]: string read GetChUnits write SetChUnits; | |
property Filename: string read sConfigName; | |
property FrameHeight: integer read fFrameHeight write SetFrameHeight; | |
property FrameWidth: integer read fFrameWidth write SetFrameWidth; {linear portion of the scan} | |
property FrameRate: double read GetFrameRate write SetFrameRate; | |
property FullFrameWidth: integer read GetFullFrameWidth; {includes sine wave rounded portion} | |
property Modified: boolean read bDirty; | |
property PixelClock: integer read fPixelClock write SetPixelClock; | |
property ScanMode: TScanMode read fScanMode write SetScanMode; | |
property VideoChCount: integer read GetVideoChCount; | |
property XFrameOffset: integer read fXFrameOffset write SetXFrameOffset; | |
property YFrameOffset: integer read fYFrameOffset write SetYFrameOffset; | |
end; | |
{The class to handle *.MPD data files. Parameters are stored in the | |
#5UserDefinedProperties stream, including comments} | |
TMPFile = class | |
private | |
bDirty: boolean; | |
sFileName: string; | |
rootStorage: IStorage; | |
streams: array[0..3] of IStream; | |
fPropertyStorage: IPropertyStorage; | |
fPropertySetStorage: IPropertySetStorage; | |
public | |
function DefaultFileName(const fileDir: string): string; | |
procedure Close(sComments: string); | |
procedure NewFile(const sNewFile: string); | |
{SetProperties stores config info and creates streams} | |
procedure SetProperties(const config: TConfiguration); | |
function Write(streamIndex: integer; var data; cbytes: integer): boolean; | |
constructor Create(const sInitialDir: string); | |
property Dirty: boolean read bDirty; | |
property Filename: string read sFileName; | |
end; | |
{*****************************************************************************} | |
{* FILES *} | |
{*****************************************************************************} | |
TFileErr = (feOK, | |
feCannotFindFile, | |
fePathNotFound, | |
feTooManyFilesOpened, | |
feAccessDenied, | |
feBadFileType, | |
feBadVersion, | |
feForceConversion, | |
feDiskFull, | |
feFileIsNotStorage, | |
feOutOfMemory, | |
feBadDiskDrive, | |
feCannotReadFile, | |
feUnknownError, | |
feBadData, | |
feUnexpectedEOF, | |
feShareViolation, | |
feInvalidHandle, | |
feFileNotAssigned, | |
feFileNotOpen, | |
feFileNotOpenForInput, | |
feFileNotOpenForOutput, | |
feInvalidInput, | |
feInvalidName, | |
feNotAPXDFile | |
); | |
TStorageNameErr = (sneOK, sneInvalidName, sneTooLong, sneInvalidChar, sneNumChar, | |
sneReservedName, sneAlreadyExists); | |
//******************************** GRAPHICS ********************************* | |
TMinMaxPt = record | |
MaxPt, MinPt: TPoint; | |
end; | |
TTrace = array of TMinMaxPt; | |
TpTrace = ^TTrace; | |
//*************************** REGION OF INTEREST **************************** | |
TSimpleROI = class | |
procedure Draw(aCanvas: TCanvas; magnification: integer); virtual; | |
end; | |
TRectangleROI = class(TSimpleROI) | |
public | |
rc: TRect; | |
procedure Draw(aCanvas: TCanvas; magnification: integer); override; | |
end; | |
TEllipseROI = class(TSimpleROI) | |
public | |
ellipse: TRect; {the bounding rectangle of the ellipse} | |
procedure Draw(aCanvas: TCanvas; magnification: integer); override; | |
end; | |
TPolygonROI = class(TSimpleROI) | |
public | |
polygon: array of TPoint; | |
procedure Draw(aCanvas: TCanvas; magnification: integer); override; | |
end; | |
{When an ROI has been defined (by adding simple ROIs), the client should: | |
Call GetPixelCount once: this returns the number of pixels in the ROI and | |
resets the enumeration | |
Call repetitively NextPtInROI; When NextPtInROI returns False, the | |
enumerator is reset} | |
TROI = class(TList) | |
private | |
rectCount, | |
rectIndex, | |
i, j: integer; | |
regionRects: array of TRect; | |
handleRGN: HRGN; | |
function GetSimpleROIs(index: integer): TSimpleROI; | |
function GetPixelCount: integer; {caches the rectangles} | |
public | |
function AddSimpleROI(Item: TSimpleROI): integer; | |
function NextPtInROI(var pt: TPoint): boolean; | |
procedure Draw(aCanvas: TCanvas; magnification: integer); | |
destructor Destroy; override; | |
property SimpleROIs[index: integer]: TSimpleROI read GetSimpleROIs; | |
property PixelCount: integer read GetPixelCount; | |
end; | |
// ============================ Registry Methods =============================== | |
function StrParse(var fullStr: string; delim: Char): string; | |
procedure SavePosToRegistry(aForm: TForm; regini: TRegistryIniFile; const section, entry: string); | |
procedure RestorePosFromRegistry(aForm: TForm; regini: TRegistryIniFile; const section, entry: string; | |
bMainForm: boolean); | |
{*****************************************************************************} | |
{* Transfer functions *} | |
{*****************************************************************************} | |
{calculates the offset of a data point in a buffer at time int64Time} | |
function TimeToPoint(int64Time, int64TimeBase, int64TimeStamp: TTimeValue): integer; | |
{reverse function} | |
function PointToTime(pointPos: integer; int64TimeBase, int64TimeStamp: TTimeValue): TTimeValue; | |
function PrefixToString(prefix: TPrefix): string; | |
function PrefixToFactor(prefix: TPrefix): double; | |
function ExpToPrefixString(exponent: integer): string; | |
function GetPrefixFromValue(value: double): TPrefix; | |
procedure TimeValToUser(timeval: TTimeValue; var value: double; var prefix: integer); | |
function TimeValToString(timeval: TTimeValue): string; | |
function SizeOfSample(dataType: TVartype): integer; | |
function TimeToFreqString(aTime: TTimeValue {in ns}): string; {Hz, kHz, MHz} | |
{*****************************************************************************} | |
{* List Box Functions *} | |
{*****************************************************************************} | |
{this procedure initializes a list box with prefixes and unit} | |
procedure FillUnitListBox(listBox: TComboBox; sUnit: string); | |
{this function returns the index of the prefix in a list box filled with prefix-unit} | |
function UnitPrefixToListBoxIndex(prefix: integer): integer; | |
function ListBoxIndexToUnitPrefix(listBoxIndex: integer): integer; | |
procedure FillTimeListBox(listBox: TComboBox); {fill a list box with ns, us, etc...} | |
procedure AbsoluteTimeToTimePrefix(absTime: TTimeValue; var dblTime: double; var timeIndex: integer); | |
{timeIndex corresponds to a value in a list box} | |
function ListBoxIndexToTimePrefix(listBoxIndex: integer): TTimeValue; | |
procedure FillInputRangeListBox(listBox: TComboBox); {fill a list box with ns, us, etc...} | |
function InputRangeToString(inputRange: TFullScaleVal): string; | |
{*****************************************************************************} | |
{* Axis Label Functions *} | |
{*****************************************************************************} | |
{timeval is a time interval; returns a decade (in us...); used for time major tick | |
marks } | |
function TimeIntervalDecade(timeval: TTimeValue): TTimeValue; | |
function FullScaleToVal(fs: TFullScaleVal): double; | |
// ============================ File I/O Methods =============================== | |
function IOErrToFileErr(code: integer): TFileErr; | |
function FileErrToStr(fe: TFileErr): string; | |
function StgErrToFileErr(hr: HResult): TFileErr; | |
// ============================ Miscellaneous ================================== | |
function FindCommonRegion(start1, end1, start2, end2: integer; | |
var commonStart, commonEnd: integer): boolean; | |
procedure NormalizeRect(var rect: TRect); | |
function PrecisionToString(aPrecision: TPrecision): string; | |
function PointStrictlyInRect(const aPt: TPoint; aRect: TRect): boolean; | |
function ScanModeToString(smode: TScanMode): string; | |
procedure MakeRectFromPts(left, top, right, bottom: integer; var rectarray: array of TPoint); | |
{******************************************************************************} | |
{*} {*} | |
{*} IMPLEMENTATION {*} | |
{*} {*} | |
{******************************************************************************} | |
uses Math, inifiles, Dialogs; | |
resourcestring | |
// FILE I/O ERRORS | |
sIOErr_FileNotFound = 'File not found'; | |
sIOErr_PathNotFound = 'Path not found'; | |
sIOErr_TooManyOpenFiles = 'Too many open files'; | |
sIOErr_AccessDenied = 'File access denied'; | |
sIOErr_InvalidHandle = 'Invalid file handle'; | |
sIOErr_NotEnoughMemory = 'Insufficient memory for this operation'; | |
sIOErr_InvalidFileAccessCode = 'Invalid file access code'; | |
sIOErr_InvalidData = 'Invalid data'; | |
sIOErr_NotEnoughStorage = 'Not enough storage'; | |
sIOErr_InvalidDrive = 'Invalid drive'; | |
sIOErr_CannotWrite = 'Error writing to file'; | |
sIOErr_CannotRead = 'Error reading from file'; | |
sIOErr_SharingViolation = 'Share violation error'; | |
sIOErr_EOF = 'Disk read error, read past end of file'; | |
sIOErr_DiskFull = 'Disk write error, disk full'; | |
sIOErr_FileNotAssigned = 'File not assigned'; | |
sIOErr_NotACompoundFile = 'Invalid file'; | |
sIOErr_InvalidName = 'Invalid file name'; | |
sIOErr_Unexpected = 'Unexpected error'; | |
sIOErr_InvalidFileType = 'Invalid file type'; | |
sIOErr_InvalidVersion = 'Invalid file version'; | |
sIOErr_FileIsNotStorage = 'The file is not a compound file'; | |
sIOErr_BadData = 'Corrupted data in file'; | |
sIOErr_ForceConversion = 'Forced file conversion'; | |
sIOErr_FileNotOpen = 'File not opened'; | |
sIOErr_FileNotOpenForInput = 'File not opened for input'; | |
sIOErr_FileNotOpenForOutput = 'File not opened for output'; | |
sIOErr_InvalidInput = 'Invalid input'; | |
sIOErr_NotAPXDFile = 'The file is not a PXD file'; | |
// Storage name error | |
sSNE_InvalidName = 'Invalid name'; | |
sSNE_TooLong = 'Name too long'; | |
sSNE_InvalidChar = 'Invalid character in name'; | |
sSNE_NumChar = 'Invalid numerical character in name'; | |
sSNE_ReservedName = 'Reserved name'; | |
sSNE_AlreadyExist = 'Name already exists'; | |
type | |
EMPConfig = class(Exception); | |
TPropSpecArray = array[0..1000] of TPropSpec; | |
TpPropSpecArray = ^TPropSpecArray; | |
TPropVariantArray = array[0..1000] of TPropVariant; | |
TpPropVariantArray = ^TPropVariantArray; | |
TStatPropStgArray = array[0..1000] of TStatPropStg; | |
TpStatPropStgArray = ^TStatPropStgArray; | |
const | |
FMTID_User_Defined_Properties: TGUID = '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}'; | |
function PrecisionToString(aPrecision: TPrecision): string; | |
begin | |
case aPrecision of | |
PREC_8_BIT: Result := '8-bit'; | |
PREC_10_BIT: Result := '10-bit'; | |
PREC_12_BIT: Result := '12-bit'; | |
PREC_14_BIT: Result := '14-bit'; | |
else Result := '16-bit'; | |
end; | |
end; | |
procedure MakeRectFromPts(left, top, right, bottom: integer; var rectarray: array of TPoint); | |
begin | |
rectarray[0].x := left; rectarray[0].y := top; | |
rectarray[1].x := right; rectarray[1].y := top; | |
rectarray[2].x := right; rectarray[2].y := bottom; | |
rectarray[3].x := left; rectarray[3].y := bottom; | |
rectarray[4].x := left; rectarray[4].y := top; | |
end; | |
// ============================ Registry Methods =============================== | |
function StrParse(var fullStr: string; delim: Char): string; | |
var delimPos: integer; | |
begin | |
delimPos := Pos(delim, fullStr); | |
if delimPos > 0 then | |
begin | |
Result := Copy(fullStr,1,Pred(delimPos)); | |
fullStr := Copy(fullStr,Succ(delimPos),Length(fullStr)); | |
end | |
else | |
Result := fullStr; | |
end; | |
procedure SavePosToRegistry(aForm: TForm; regini: TRegistryIniFile; const section, entry: string); | |
var buffer: array[0..79] of Char; | |
windowPlacement: TWindowPlacement; | |
begin | |
windowPlacement.Length := SizeOf(windowPlacement); | |
GetWindowPlacement(aForm.Handle, @windowPlacement); | |
WVSPrintf(buffer, '%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i', @windowPlacement); | |
regini.WriteString(section, entry, StrPas(buffer)); | |
end; | |
procedure RestorePosFromRegistry(aForm: TForm; regini: TRegistryIniFile; const section, entry: string; | |
bMainForm: boolean); | |
var buffer: string; | |
windowPlacement: TWindowPlacement; | |
begin | |
buffer := regini.ReadString(section, entry, ''); | |
FillChar(windowPlacement, SizeOf(windowPlacement), 0); | |
windowPlacement.Length := SizeOf(windowPlacement); | |
if buffer <> '' then | |
begin | |
StrToIntDef(StrParse(buffer, ','), 0); | |
with windowPlacement do | |
begin | |
flags := StrToInt(StrParse(buffer, ',')); | |
showCmd := StrToInt(StrParse(buffer, ',')); | |
ptMinPosition.x := StrToInt(StrParse(buffer, ',')); | |
ptMinPosition.y := StrToInt(StrParse(buffer, ',')); | |
ptMaxPosition.x := StrToInt(StrParse(buffer, ',')); | |
ptMaxPosition.y := StrToInt(StrParse(buffer, ',')); | |
rcNormalPosition.Left := StrToInt(StrParse(buffer, ',')); | |
rcNormalPosition.Top := StrToInt(StrParse(buffer, ',')); | |
rcNormalPosition.Right := StrToInt(StrParse(buffer, ',')); | |
rcNormalPosition.Bottom := StrToInt(StrParse(buffer, ',')); | |
case ShowCmd of | |
sw_showMinimized, | |
sw_showminnoactive, | |
sw_minimize: | |
aForm.WindowState := wsMinimized; | |
sw_showmaximized: | |
aForm.WindowState := wsMaximized; | |
end; | |
end; | |
SetWindowPlacement(aForm.Handle, @windowPlacement); | |
end | |
else | |
if bMainForm then | |
with windowPlacement do | |
begin | |
showCmd := SW_SHOW; | |
if not SystemParametersInfo(SPI_GETWORKAREA, 0, @rcNormalPosition, 0) then | |
rcNormalPosition := Rect(0, 0, 799, 599); | |
SetWindowPlacement(aForm.Handle, @windowPlacement); | |
end; | |
end; | |
{*****************************************************************************} | |
{* Transfer functions *} | |
{*****************************************************************************} | |
function PrefixToString(prefix: TPrefix): string; | |
begin | |
case prefix of | |
tpXENNO: Result := 'x'; | |
tpYOCTO: Result := 'y'; | |
tpZEPTO: Result := 'z'; | |
tpATTO: Result := 'a'; | |
tpFEMTO: Result := 'f'; | |
tpPICO: Result := 'p'; | |
tpNANO: Result := 'n'; | |
tpMICRO: Result := #181; | |
tpMILLI: Result := 'm'; | |
tpUNITY : Result := ''; | |
tpKILO: Result := 'k'; | |
tpMEGA: Result := 'M'; | |
tpGIGA: Result := 'G'; | |
tpTERA: Result := 'T'; | |
tpPETA: Result := 'P'; | |
tpECTA: Result := 'E'; | |
tpZETTA: Result := 'Z'; | |
tpYOTTA: Result := 'Y'; | |
tpXENNA: Result := 'X'; | |
tpNONE: Result := ''; | |
else | |
Result := ''; | |
end; | |
end; | |
function PrefixToFactor(prefix: TPrefix): double; | |
begin | |
case prefix of | |
tpXENNO: Result := 1E-27; | |
tpYOCTO: Result := 1E-24; | |
tpZEPTO: Result := 1E-21; | |
tpATTO: Result := 1E-18; | |
tpFEMTO: Result := 1E-15; | |
tpPICO: Result := 1E-12; | |
tpNANO: Result := 1E-9; | |
tpMICRO: Result := 1E-6; | |
tpMILLI: Result := 1E-3; | |
tpUNITY : Result := 1; | |
tpKILO: Result := 1E+3; | |
tpMEGA: Result := 1E+6; | |
tpGIGA: Result := 1E+9; | |
tpTERA: Result := 1E+12; | |
tpPETA: Result := 1E+15; | |
tpECTA: Result := 1E+18; | |
tpZETTA: Result := 1E+21; | |
tpYOTTA: Result := 1E+24; | |
tpXENNA: Result := 1E+27; | |
tpNONE: Result := 1; | |
else | |
Result := 1; | |
end; | |
end; | |
function ExpToPrefixString(exponent: integer): string; | |
begin | |
case exponent of | |
-27: Result := 'x'; | |
-24: Result := 'y'; | |
-21: Result := 'z'; | |
-18: Result := 'a'; | |
-15: Result := 'f'; | |
-12: Result := 'p'; | |
-9: Result := 'n'; | |
-6: Result := #181; | |
-3: Result := 'm'; | |
0 : Result := ''; | |
3: Result := 'k'; | |
6: Result := 'M'; | |
9: Result := 'G'; | |
12: Result := 'T'; | |
15: Result := 'P'; | |
18: Result := 'E'; | |
21: Result := 'Z'; | |
24: Result := 'Y'; | |
27: Result := 'X'; | |
else | |
Result := ''; | |
end; | |
end; | |
{This function chooses the most appropriate prefix for the value | |
if value is too small, returns tpZERO} | |
function GetPrefixFromValue(value: double): TPrefix; | |
begin | |
value := Abs(value); | |
if value <= 1E-30 then | |
Result := tpZERO | |
else if value < 1E-24 then | |
Result := tpXENNO | |
else if value < 1E-21 then | |
Result := tpYOCTO | |
else if value < 1E-18 then | |
Result := tpZEPTO | |
else if value < 1E-15 then | |
Result := tpATTO | |
else if value < 1E-12 then | |
Result := tpFEMTO | |
else if value < 1E-9 then | |
Result := tpPICO | |
else if value < 1E-6 then | |
Result := tpNANO | |
else if value < 1E-3 then | |
Result := tpMICRO | |
else if value < 1E-0 then | |
Result := tpMILLI | |
else if value < 1E+3 then | |
Result := tpUNITY | |
else if value < 1E+6 then | |
Result := tpKILO | |
else if value < 1E+9 then | |
Result := tpMEGA | |
else if value < 1E+12 then | |
Result := tpGIGA | |
else if value < 1E+15 then | |
Result := tpTERA | |
else if value < 1E+18 then | |
Result := tpPETA | |
else if value < 1E+21 then | |
Result := tpECTA | |
else if value < 1E+24 then | |
Result := tpZETTA | |
else if value < 1E+27 then | |
Result := tpYOTTA | |
else if value < 1E+30 then | |
Result := tpXENNA | |
else | |
Result := tpXENNA; | |
end; | |
function SizeOfSample(dataType: TVartype): integer; | |
begin | |
case dataType of | |
VT_I2: Result := SizeOf(int16); | |
VT_I4: Result := SizeOf(int32); | |
VT_R4: Result := SizeOf(single); | |
VT_R8: Result := SizeOf(double); | |
VT_UI2: Result := SizeOf(int16); {12-bit integer} | |
else | |
Result := SizeOf(int16); | |
end; | |
end; | |
{! in a buffer, a time stamp is always > than any time, i.e. the time stamp is the | |
time of the last point pushed in the buffer} | |
function TimeToPoint(int64Time, int64TimeBase, int64TimeStamp: TTimeValue): integer; | |
begin | |
TimeToPoint := (int64TimeStamp - int64Time)div int64TimeBase; | |
end; | |
function PointToTime(pointPos: integer; int64TimeBase, int64TimeStamp: TTimeValue): TTimeValue; | |
begin | |
PointToTime := int64TimeStamp - pointPos * int64TimeBase; | |
end; | |
procedure TimeValToUser(timeval: TTimeValue; var value: double; var prefix: integer); | |
begin | |
if timeval = 0 then | |
begin | |
value := 0; | |
prefix := 0; | |
end | |
else if Abs(timeval) >= Round(1e09) then | |
begin | |
value := timeval div Round(1e09); | |
prefix := 0; | |
end | |
else if Abs(timeval) >= Round(1e06) then | |
begin | |
value := timeval div Round(1e06); | |
prefix := -3; {ms} | |
end | |
else if Abs(timeval) >= Round(1e03) then | |
begin | |
value := timeval div Round(1e03); | |
prefix := -6; {us} | |
end | |
end; | |
function TimeValToString(timeval: TTimeValue): string; | |
var cDays, cHours, cMin: integer; | |
nSec: double; | |
fmtTimeStr: string[63]; | |
begin | |
if timeval = 0 then | |
Result := '0s' | |
else | |
try | |
if Abs(timeval) > Round(1e09) then | |
begin | |
if Abs(timeval) > Round(24 * 60 * 60 * 1e09) then | |
begin | |
cDays := Abs(Timeval) div Round(24 * 60 * 60 * 1e09); | |
cHours := (Abs(Timeval) - cDays * Round(24 * 60 * 60 * 1e09)) div Round(60 * 60 * 1e09); | |
cMin := (Abs(Timeval) - cDays * Round(24 * 60 * 60 * 1e09) - cHours * Round(60 * 60 * 1e09)) div Round(60 * 1e09); | |
nSec := (Abs(Timeval) - cDays * Round(24 * 60 * 60 * 1e09) - cHours * Round(60 * 60 * 1e09) - cMin * Round(60 * 1e09)) / Round(1e09); | |
if cDays > 1 then fmtTimeStr := '%ddays' else fmtTimeStr := '%dday'; | |
if cHours > 1 then fmtTimeStr := fmtTimeStr + ' %dhrs %dmin %.5ds' | |
else fmtTimeStr := fmtTimeStr + ' %dhr %dmin %.5ds'; | |
result := Format(fmtTimeStr , [cDays, cHours, cMin, nSec]); | |
if timeVal < 0 then result := '- ' + Result; | |
end | |
else if Abs(timeval) > Round(60 * 60 * 1e09) then | |
begin | |
cHours := Abs(Timeval) div Round(60 * 60 * 1e09); | |
cMin := (Abs(Timeval) - cHours * Round(60 * 60 * 1e09)) div Round(60 * 1e09); | |
nSec := (Abs(Timeval) - cHours * Round(60 * 60 * 1e09) - cMin * Round(60 * 1e09)) div Round(1e09); | |
if cHours > 1 then fmtTimeStr := '%dhrs %dmin %.5ds' | |
else fmtTimeStr := '%dhr %dmin %.5ds'; | |
result := Format(fmtTimeStr , [cHours, cMin, nSec]); | |
if timeVal < 0 then result := '- ' + Result; | |
end | |
else if Abs(timeval) > Round(60 * 1e09) then | |
begin | |
cMin := Abs(Timeval) div Round(60 * 1e09); | |
nSec := (Abs(Timeval) - cMin * Round(60 * 1e09)) div Round(1e09); | |
if timeVal >= 0 then | |
result := Format('%dmin %.5ds', [cMin, nSec]) | |
else | |
result := Format('- %dmin %.5ds', [cMin, nSec]); | |
end | |
else | |
result := Format('%.5d', [timeval div Round(1e09)]) + 's'; | |
end | |
else if Abs(timeval) > Round(1e06) then | |
result := Format('%.5d', [timeval div Round(1e06)]) + 'ms' | |
else if Abs(timeval) > 1e03 then | |
result := Format('%.5d', [timeval div Round(1e03)]) + Chr(181) + 's' | |
else | |
result := Format('%.5d', [timeval]) + 'ns'; | |
except | |
On EInvalidOp do Result := 'Infinite time'; | |
end; | |
end; | |
function TimeToFreqString(aTime: TTimeValue {in ns}): string; {Hz, kHz, MHz} | |
var freq: double; | |
begin | |
if aTime = 0 then | |
Result := '?Hz' | |
else | |
begin | |
freq := 1e09 / aTime; | |
if Abs(freq) < 1000 then | |
Result := Format('%.3g', [freq]) + 'Hz' | |
else if Abs(freq) < 1000000 then | |
Result := Format('%.3g', [freq/1000]) + 'kHz' | |
else | |
Result := Format('%.3g', [freq/1000000]) + 'MHz' | |
end; | |
end; | |
{*****************************************************************************} | |
{* List Box Functions *} | |
{*****************************************************************************} | |
procedure FillUnitListBox(listBox: TComboBox; sUnit: string); | |
begin | |
with listBox, listBox.Items do | |
begin | |
Clear; | |
Add('x' + sUnit); | |
Add('y' + sUnit); | |
Add('z' + sUnit); | |
Add('a' + sUnit); | |
Add('f' + sUnit); | |
Add('p' + sUnit); | |
Add('n' + sUnit); | |
Add(#181 + sUnit); | |
Add('m' + sUnit); | |
Add(sUnit); | |
Add('k' + sUnit); | |
Add('M' + sUnit); | |
Add('G' + sUnit); | |
Add('T' + sUnit); | |
Add('P' + sUnit); | |
Add('E' + sUnit); | |
Add('Z' + sUnit); | |
Add('Y' + sUnit); | |
Add('X' + sUnit); | |
end; | |
end; | |
function UnitPrefixToListBoxIndex(prefix: integer): integer; | |
begin | |
Result := (27 + prefix) div 3; | |
end; | |
function ListBoxIndexToUnitPrefix(listBoxIndex: integer): integer; | |
begin | |
Result := listBoxIndex * 3 - 27; | |
end; | |
procedure FillTimeListBox(listBox: TComboBox); {fill a list box with ns, us, etc...} | |
begin | |
with listBox, listBox.Items do | |
begin | |
Clear; | |
Add('ns'); | |
Add(Chr(181) + 's'); | |
Add('ms'); | |
Add('s'); | |
Add('min'); | |
Add('hr'); | |
end; | |
end; | |
procedure FillInputRangeListBox(listBox: TComboBox); | |
var i: TFullScaleVal; | |
begin | |
with listBox, listBox.Items do | |
begin | |
Clear; | |
for i := pm_42V to pm_0_2V do | |
Add(InputRangeToString(i)); | |
end; | |
end; | |
procedure AbsoluteTimeToTimePrefix(absTime: TTimeValue; var dblTime: double; var timeIndex: integer); | |
var posTime: TTimeValue; | |
begin | |
posTime := Abs(absTime); | |
if absTime = 0 then | |
begin | |
timeIndex := 3; {seconds} | |
dblTime := 0; | |
end | |
else if posTime > Round(60 * 60 * 1e09) then | |
begin | |
timeIndex := 5; | |
dblTime := absTime div Round(60 * 60 * 1e09); | |
end | |
else if posTime > 60 * 1e09 then | |
begin | |
timeIndex := 4; | |
dblTime := absTime div Round(60 * 1e09); | |
end | |
else if posTime > 1e09 then | |
begin | |
timeIndex := 3; | |
dblTime := absTime div Round(1e09); | |
end | |
else if posTime > 1e06 then | |
begin | |
timeIndex := 2; | |
dblTime := absTime div Round(1e06); | |
end | |
else if posTime > 1e03 then | |
begin | |
timeIndex := 1; | |
dblTime := absTime div Round(1e03); | |
end | |
else | |
begin | |
timeIndex := 0; | |
dblTime := absTime; | |
end; | |
end; | |
function ListBoxIndexToTimePrefix(listBoxIndex: integer): TTimeValue; | |
begin | |
case listBoxIndex of | |
0: Result := 1; | |
1: Result := Round(1e03); | |
2: Result := Round(1e06); | |
3: Result := Round(1e09); | |
4: Result := Round(60 * 1e09); | |
5: Result := Round(3600 * 1e09); | |
else | |
Result := 1; | |
end; | |
end; | |
function FullScaleToVal(fs: TFullScaleVal): double; | |
begin | |
case fs of | |
pm_42V: Result := 42.0; | |
pm_20V: Result := 20.0; | |
pm_10V: Result := 10.0; | |
pm_5V: Result := 5.0; | |
pm_2V: Result := 2.0; | |
pm_1V: Result := 1.0; | |
pm_0_5V: Result := 0.5; | |
pm_0_2V: Result := 0.2; | |
else | |
Result := 0; | |
end; | |
end; | |
function InputRangeToString(inputRange: TFullScaleVal): string; | |
begin | |
case inputRange of | |
pm_42V: Result := Chr(177) + '42V'; | |
pm_20V: Result := Chr(177) + '20V'; | |
pm_10V: Result := Chr(177) + '10V'; | |
pm_5V: Result := Chr(177) + '5V'; | |
pm_2V: Result := Chr(177) + '2V'; | |
pm_1V: Result := Chr(177) + '1V'; | |
pm_0_5V: Result := Chr(177) + '0.5V'; | |
pm_0_2V: Result := Chr(177) + '0.2V'; | |
else | |
Result := ''; | |
end; | |
end; | |
{****************************** Axis Label Functions *******************************} | |
{timeval is a time interval; returns a decade (in us...); used for time major tick | |
marks } | |
function TimeIntervalDecade(timeval: TTimeValue): TTimeValue; | |
var realTime: double; | |
begin | |
timeval := Abs(timeval); | |
if timeval = 0 then | |
Result := 0 | |
else | |
if timeval > 60 * 60 * 1e09 then | |
begin | |
{The unit will be in hours} | |
realTime := timeval / (60 * 60 * 1e09); | |
realTime := Round( (Ln(realTime) / Ln(10)) + 1) * (60 * 60 * 1e09); | |
Result := Round(realTime); | |
end | |
else if timeval > 60 * 1e09 then | |
begin | |
{The unit will be in minutes} | |
realTime := timeval / (60 * 1e09); | |
realTime := Round( (Ln(realTime) / Ln(10)) + 1) * (60 * 1e09); | |
Result := Round(realTime); | |
end | |
else | |
begin | |
{The unit will be in seconds or decimal fractions of a second} | |
realTime := timeval; | |
Result := Round(Ln(realTime) / Ln(10)) + 1; | |
end; | |
end; | |
function IOErrToFileErr(code: integer): TFileErr; | |
begin | |
case code of | |
2: Result := feCannotFindFile; | |
3: Result := fePathNotFound; | |
4: Result := feTooManyFilesOpened; | |
5: Result := feAccessDenied; | |
6: Result := feInvalidHandle; | |
8: Result := feOutOfMemory; | |
100: Result := feUnexpectedEOF; | |
101: Result := feDiskFull; | |
102: Result := feFileNotAssigned; | |
103: Result := feFileNotOpen; | |
104: Result := feFileNotOpenForInput; | |
105: Result := feFileNotOpenForOutput; | |
106: Result := feInvalidInput; | |
else | |
Result := feUnknownError; | |
end; | |
end; | |
function FileErrToStr(fe: TFileErr): string; | |
begin | |
case fe of | |
feCannotFindFile: Result := sIOErr_FileNotFound; | |
fePathNotFound: Result := sIOErr_PathNotFound; | |
feTooManyFilesOpened: Result := sIOErr_TooManyOpenFiles; | |
feAccessDenied: Result := sIOErr_AccessDenied; | |
feBadFileType: Result := sIOErr_InvalidFileType; | |
feBadVersion: Result := sIOErr_InvalidVersion; | |
feForceConversion: Result := sIOErr_ForceConversion; | |
feDiskFull: Result := sIOErr_DiskFull; | |
feFileIsNotStorage: Result := sIOErr_FileIsNotStorage; | |
feOutOfMemory: Result := sIOErr_NotEnoughMemory; | |
feBadDiskDrive: Result := sIOErr_InvalidDrive; | |
feCannotReadFile: Result := sIOErr_CannotRead; | |
feUnknownError: Result := sIOErr_Unexpected; | |
feBadData: Result := sIOErr_BadData; | |
feUnexpectedEOF: Result := sIOErr_EOF; | |
feShareViolation: Result := sIOErr_SharingViolation; | |
feInvalidHandle: Result := sIOErr_InvalidHandle; | |
feFileNotAssigned: Result := sIOErr_FileNotAssigned; | |
feFileNotOpen: Result := sIOErr_FileNotOpen; | |
feFileNotOpenForInput: Result := sIOErr_FileNotOpenForInput; | |
feFileNotOpenForOutput: Result := sIOErr_FileNotOpenForOutput; | |
feInvalidInput: Result := sIOErr_InvalidInput; | |
feInvalidName: Result := sIOErr_InvalidName; | |
feNotAPXDFile: Result := sIOErr_NotAPXDFile; | |
else | |
Result := sIOErr_Unexpected; | |
end; | |
end; | |
// ***************************************************************************** | |
// | |
// ROI Methods | |
// | |
// ***************************************************************************** | |
procedure TSimpleROI.Draw(aCanvas: TCanvas; magnification: integer); | |
begin | |
with aCanvas do | |
begin | |
Pen.Mode := pmCopy; | |
Pen.Color := clWhite; | |
Pen.Width := 1; | |
Pen.Style := psDot; | |
end; | |
end; | |
procedure TRectangleROI.Draw(aCanvas: TCanvas; magnification: integer); | |
var magRect: TRect; | |
begin | |
inherited Draw(aCanvas, magnification); | |
magRect := rc; | |
NormalizeRect(magRect); | |
magRect.Left := magRect.Left * magnification; | |
magRect.Top := magRect.Top * magnification; | |
magRect.Right := (magRect.Right + 1) * magnification - 1; | |
magRect.Bottom := (magRect.Bottom + 1) * magnification - 1; | |
aCanvas.FrameRect(magRect); | |
end; | |
procedure TEllipseROI.Draw(aCanvas: TCanvas; magnification: integer); | |
var magRect: TRect; | |
begin | |
inherited Draw(aCanvas, magnification); | |
magRect := ellipse; | |
NormalizeRect(magRect); | |
magRect.Left := magRect.Left * magnification; | |
magRect.Top := magRect.Top * magnification; | |
magRect.Right := (magRect.Right + 1) * magnification - 1; | |
magRect.Bottom := (magRect.Bottom + 1) * magnification - 1; | |
aCanvas.Arc(magRect.Left, magRect.Top, magRect.Right, magRect.Bottom, | |
magRect.Left, magRect.Top + (magRect.Bottom - magRect.Top + 1) div 2, | |
magRect.Left, magRect.Top + (magRect.Bottom - magRect.Top + 1) div 2); | |
end; | |
procedure TPolygonROI.Draw(aCanvas: TCanvas; magnification: integer); | |
var newPolygon: array of TPoint; {has one more element to close the array} | |
i: integer; | |
begin | |
inherited Draw(aCanvas, magnification); | |
SetLength(newPolygon, Length(Polygon) + 1); | |
for i := 0 to Length(Polygon) - 1 do | |
begin {to center polygon} | |
newPolygon[i].X := polygon[i].X * magnification + magnification div 2; | |
newPolygon[i].Y := polygon[i].Y * magnification + magnification div 2; | |
end; | |
newPolygon[Length(Polygon)] := newPolygon[0]; {closes the polygon} | |
aCanvas.Polyline(newPolygon); | |
end; | |
function TROI.GetSimpleROIs(index: integer): TSimpleROI; | |
begin | |
if (index >= 0) and (index < count) then | |
Result := TSimpleROI(Items[index]) | |
else | |
Result := nil; | |
end; | |
type | |
{a better substitute for PRgnData (in Windows.pas)} | |
TRGNDataBuffer = record | |
rdh: TRgnDataHeader; | |
rects: array[0..0] of TRect; | |
end; | |
TpRGNDataBuffer = ^TRGNDataBuffer; | |
function TROI.GetPixelCount: integer; | |
var pRegionBuffer: TpRGNDataBuffer; | |
k: integer; | |
begin | |
Result := 0; | |
pRegionBuffer := AllocMem(1024); | |
try | |
if GetRegionData(handleRGN, 1024, PRgnData(pRegionbuffer)) <> 0 then | |
with pRegionbuffer^ do | |
if rdh.nCount > 0 then | |
begin | |
for k := 0 to rdh.nCount - 1 do | |
Result := Result + (rects[k].Right - rects[k].Left + 1) * | |
(rects[k].Bottom - rects[k].Top + 1); | |
{cache the rectangles for enumeration} | |
rectCount := rdh.nCount; | |
SetLength(regionRects, rectCount); | |
for k := 0 to rectCount - 1 do | |
regionRects[k] := rects[k]; | |
rectIndex := 0; | |
i := regionRects[0].Left - 1; | |
j := regionRects[0].Top; | |
end; | |
finally | |
FreeMem(pRegionBuffer, 1024); | |
end; | |
end; | |
function TROI.NextPtInROI(var pt: TPoint): boolean; | |
begin | |
Result := False; | |
i := i + 1; | |
if i > regionRects[rectIndex].Right then | |
begin | |
if j < regionRects[rectIndex].Bottom then | |
begin | |
j := j + 1; | |
i := regionRects[rectIndex].Left; | |
Result := True; | |
end | |
else | |
begin | |
rectIndex := rectIndex + 1; | |
if rectIndex < rectCount - 1 then | |
begin | |
rectIndex := rectIndex + 1; | |
i := regionRects[rectIndex].Left; | |
j := regionRects[rectIndex].Top; | |
Result := True; | |
end | |
else | |
begin {result := False} | |
rectIndex := 0; | |
i := regionRects[0].Left - 1; | |
j := regionRects[0].Top; | |
end; | |
end; | |
end | |
else | |
Result := True; | |
if Result = True then | |
begin | |
pt.X := i; | |
pt.Y := j; | |
end; | |
end; | |
function TROI.AddSimpleROI(Item: TSimpleROI): integer; | |
var itemHandle: HRgn; | |
begin | |
Result := -1; | |
if Item is TRectangleROI then | |
with Item as TRectangleROI do | |
itemHandle := CreateRectRgn(rc.Left, rc.Right + 1, rc.Top, rc.Bottom + 1) | |
else if Item is TEllipseROI then | |
with Item as TEllipseROI do | |
itemHandle := CreateEllipticRgn(ellipse.Left, ellipse.Right, ellipse.Top, ellipse.Bottom) | |
else | |
with Item as TPolygonROI do {very dubious argument: polygon[0]} | |
itemHandle := CreatePolygonRgn(polygon[0], Length(polygon), ALTERNATE); | |
if Count = 0 then | |
begin | |
handleRgn := itemHandle; | |
Result := Add(Item); | |
end | |
else | |
if CombineRgn(handleRgn, handleRgn, itemHandle, RGN_OR) <> 0 {<> ERROR} then | |
begin | |
Result := Add(Item); | |
DeleteObject(itemHandle); | |
end; | |
end; | |
procedure TROI.Draw(aCanvas: TCanvas; magnification: integer); | |
var k: integer; | |
begin | |
if Count > 0 then | |
for k := 0 to Count - 1 do | |
TSimpleROI(Items[k]).Draw(aCanvas, magnification); | |
end; | |
destructor TROI.Destroy; | |
var k: integer; | |
begin | |
if Count > 0 then | |
for k := 0 to Count - 1 do | |
TSimpleROI(Items[k]).Free; | |
{destroys handleRgn} | |
if handleRgn <> 0 then DeleteObject(handleRgn); | |
inherited Destroy; | |
end; | |
function FindCommonRegion(start1, end1, start2, end2: integer; | |
var commonStart, commonEnd: integer): boolean; | |
begin | |
{make sure that end1 <= start1} | |
if start1 > end1 then | |
begin | |
commonStart := start1; | |
start1 := end1; | |
end1 := commonStart; | |
end; | |
if start2 > end2 then | |
begin | |
commonStart := start2; | |
start2 := end2; | |
end2 := commonStart; | |
end; | |
if start1 > start2 then | |
begin | |
commonStart := start1; | |
commonEnd := end1; | |
// start1 := start2; no need | |
end1 := end2; | |
start2 := commonStart; | |
end2 := commonEnd; | |
end; | |
if start2 > end1 then | |
Result := False | |
else | |
begin | |
commonStart := start2; | |
if end2 <= end1 then | |
commonEnd := end2 | |
else | |
commonEnd := end1; | |
Result := True; | |
end; | |
end; | |
procedure NormalizeRect(var rect: TRect); | |
var i: integer; | |
begin | |
if rect.Left > rect.Right then | |
begin | |
i := rect.Left; | |
rect.Left := rect.Right; | |
rect.Right := i; | |
end; | |
if rect.Top > rect.Bottom then | |
begin | |
i := rect.Top; | |
rect.Top := rect.Bottom; | |
rect.Bottom := i; | |
end; | |
end; | |
{******************************** CONFIGURATION ********************************} | |
function TConfiguration.GetChAnalogFreqs(chIndex: integer): double; | |
begin | |
Result := GetFrameRate * fChDataPtsPerFrames[chIndex]; | |
end; | |
function TConfiguration.GetChConvFactors(chIndex: integer): double; | |
begin | |
Result := fChConvFactors[chIndex]; | |
end; | |
function TConfiguration.GetChCount: integer; | |
begin | |
Result := AnalogChCount + VideoChCount; | |
end; | |
function TConfiguration.GetChDataPtsPerFrames(chIndex: integer): integer; | |
begin | |
Result := fChDataPtsPerFrames[chIndex]; | |
end; | |
function TConfiguration.GetChEnabled(chIndex: integer): boolean; | |
begin | |
Result := fChEnabled[chIndex]; | |
end; | |
function TConfiguration.GetChInputRanges(chIndex: integer): TFullScaleVal; | |
begin | |
Result := fChInputRanges[chIndex]; | |
end; | |
function TConfiguration.GetChNames(chIndex: integer): string; | |
begin | |
Result := fChNames[chIndex]; | |
end; | |
function TConfiguration.GetChOffsets(chIndex: integer): double; | |
begin | |
Result := fChOffsets[chIndex]; | |
end; | |
function TConfiguration.GetChPrefixes(chIndex: integer): TPrefix; | |
begin | |
Result := fChPrefixes[chIndex]; | |
end; | |
function TConfiguration.GetChUnits(chIndex: integer): string; | |
begin | |
Result := fChUnits[chIndex]; | |
end; | |
{The number of points collected = linear portion (frameWidth) + retrace sine points | |
which are discarded} | |
function TConfiguration.GetFullFrameWidth: integer; | |
begin | |
Result := Muldiv(FrameWidth, 5, 4); | |
end; | |
procedure TConfiguration.DefaultConfig; | |
var i: integer; | |
begin | |
sConfigName := ''; | |
fXFrameOffset := 0; | |
fYFrameOffset := 0; | |
fFrameWidth := 500; | |
fFrameHeight := 500; | |
fPixelClock := 16; {1.25 MHz} | |
for i := 0 to MAX_CH - 1 do | |
begin | |
fChConvFactors[i] := 1; | |
fChDataPtsPerFrames[i] := 1000; | |
fChInputRanges[i]:= pm_10V; | |
fChNames[i]:= 'Channel ' + IntToStr(i+1); | |
fChOffsets[i] := 0; | |
fChPrefixes[i] := tpUNITY; | |
fChUnits[i] := 'V'; | |
end; | |
fChEnabled[0] := True; | |
fChEnabled[1] := False; | |
fChEnabled[2] := False; | |
fChEnabled[3] := False; | |
end; | |
function TConfiguration.GetAnalogChCount: integer; | |
begin | |
Result := 0; | |
if fChEnabled[2] then Result := 1; | |
if fChEnabled[3] then Result := Result + 1; | |
end; | |
function TConfiguration.GetFrameRate: double; | |
begin | |
Result := 1 / (fullFrameWidth * fFrameHeight * fPixelClock * BASE_CLOCK); | |
end; | |
procedure TConfiguration.GetMaxFrameRate(iframeWidth, iFrameHeight: integer; var newFrameRate: double; | |
var newPixelRate: integer); | |
var freq: double; | |
begin | |
if iframeWidth < 100 then | |
freq := 1700 {1.7 kHz limit} | |
else | |
{125 pixels: 1.7 kHz ; 625 pixels: 1.25 kHz} | |
freq := 1700 - 4 * (Muldiv(iFrameWidth, 5, 4) - 125) / 5; | |
newPixelRate := Floor(((1 / (freq * 2)) / Muldiv(iFrameWidth, 5, 4)) / 5e-8); | |
newFrameRate := 1 / (Muldiv(iFrameWidth, 5, 4) * iFrameHeight * newPixelRate * BASE_CLOCK); | |
end; | |
function TConfiguration.GetVideoChCount: integer; | |
begin | |
Result := 0; | |
if fChEnabled[0] then Result := 1; | |
if fChEnabled[1] then Result := Result + 1; | |
end; | |
procedure TConfiguration.SetChConvFactors(chIndex: integer; newconvfactor: double); | |
begin | |
fChConvFactors[chIndex] := newconvfactor; | |
end; | |
procedure TConfiguration.SetChDataPtsPerFrames(chIndex: integer; newDataPtsPerFrames: integer); | |
begin | |
if newDataPtsPerFrames < 0 then Exit; | |
if newDataPtsPerFrames <= fFrameWidth * fFrameHeight then | |
begin | |
bDirty := True; | |
fChDataPtsPerFrames[chIndex] := newDataPtsPerFrames; | |
end; | |
end; | |
procedure TConfiguration.SetChEnabled(chIndex: integer; newChEnabled: boolean); | |
begin | |
fChEnabled[chIndex] := newChEnabled; | |
bDirty := True; | |
end; | |
procedure TConfiguration.SetChInputRanges(chIndex: integer; newChInputRanges: TFullScaleVal); | |
begin | |
fChInputRanges[chIndex] := newChInputRanges; | |
bDirty := True; | |
end; | |
procedure TConfiguration.SetChNames(chIndex: integer; newChNames: string); | |
begin | |
fChNames[chIndex] := newChNames; | |
bDirty := True; | |
end; | |
procedure TConfiguration.SetChOffsets(chIndex: integer; newChOffsets: double); | |
begin | |
fChOffsets[chIndex] := newChOffsets; | |
bDirty := True; | |
end; | |
procedure TConfiguration.SetChPrefixes(chIndex: integer; newChPrefixes: TPrefix); | |
begin | |
fChPrefixes[chIndex] := newChPrefixes; | |
bDirty := True; | |
end; | |
procedure TConfiguration.SetChUnits(chIndex: integer; newChUnits: string); | |
begin | |
fChUnits[chIndex] := newChUnits; | |
bDirty := True; | |
end; | |
procedure TConfiguration.SetFrameHeight(newHeight: integer); | |
begin | |
if (newHeight <= 500) and (newHeight >= 10) then | |
begin | |
newHeight := (newHeight div 2) * 2; | |
fFrameHeight := newHeight; | |
bDirty := True; | |
end | |
else | |
Raise EMPConfig.Create('Frame height must be between 10 and 500 lines'); | |
end; | |
procedure TConfiguration.SetFrameRate(newRate: double); | |
var newPixelClock: integer; | |
lineFreq, maxFreq: double; | |
begin | |
if newRate <= 0 then Raise EMPConfig.Create('Invalid frame rate'); | |
lineFreq := (newRate * fFrameHeight) / 2; | |
if fFrameWidth < 100 then maxFreq := 1700 else maxFreq := 1700 - 4 * (fullFrameWidth - 125) / 5; | |
if lineFreq <= maxFreq then | |
begin | |
newPixelClock := Floor(((1 / (lineFreq * 2)) / fullFrameWidth) / 5e-8); | |
{the pixel clock must be <= 2.5 MHz and >= 20 kHz with a 20 MHz timebase} | |
if (newpixelClock >= 8) and (newpixelClock <= 1000) then | |
begin | |
fPixelClock := newPixelClock; | |
bDirty := True; | |
end; | |
end; | |
end; | |
function TConfiguration.PixelRateToFrameRate(newPixelRate, iframeWidth, iframeHeight: integer; var newFrameRate: double): boolean; | |
var lineFreq, maxFreq: double; | |
begin | |
newFrameRate := 1 / (Muldiv(iframeWidth, 5, 4) * newPixelRate * iframeHeight * 5e-8); | |
lineFreq := (newFrameRate * iframeHeight) / 2; | |
if iFrameWidth < 100 then maxFreq := 1700 else maxFreq := 1700 - 4 * (Muldiv(iframeWidth, 5, 4) - 125) / 5; | |
if lineFreq <= maxFreq then | |
Result := True | |
else | |
Result := False; | |
end; | |
function TConfiguration.FrameRateToPixelRate(newFrameRate: double; iframeWidth, iframeHeight: integer; var newPixelRate: integer): boolean; | |
var lineFreq: double; | |
maxFreq: double; | |
begin | |
Result := True; | |
if newFrameRate <= 0 then | |
Result := False | |
else | |
begin | |
lineFreq := (newFrameRate * iframeHeight) / 2; | |
if iFrameWidth < 100 then maxFreq := 1700 else maxFreq := 1700 - 4 * (Muldiv(iframeWidth, 5, 4) - 125) / 5; | |
if lineFreq <= maxFreq then | |
begin | |
newPixelRate := Floor( ( (1 / (lineFreq * 2) ) / (Muldiv(iframeWidth, 5, 4)) / 5e-8)); | |
{the pixel clock must be <= 2.5 MHz and >= 20 kHz with a 20 MHz timebase} | |
if newPixelRate < 8 then Result := False; | |
end | |
else | |
Result := False; | |
end; | |
if Result = False then | |
GetMaxFrameRate(iframeWidth, iFrameHeight, newFrameRate, newPixelRate); | |
end; | |
procedure TConfiguration.SetFrameWidth(newWidth: integer); | |
begin | |
if (newWidth <= 500) and (newWidth >= 10) then | |
begin | |
fFrameWidth := newWidth; | |
bDirty := True; | |
end | |
else | |
Raise EMPConfig.Create('Frame width must be between 10 and 500 pixels'); | |
end; | |
procedure TConfiguration.SetPixelClock(newClockRate: integer); | |
begin | |
if (newClockRate >= 8) and (newClockRate <= 1000) then | |
begin | |
fPixelClock := newClockRate; | |
bDirty := True; | |
end; | |
end; | |
procedure TConfiguration.SetScanMode(newMode: TScanMode); | |
begin | |
fScanMode := newMode; | |
bDirty := True; | |
end; | |
procedure TConfiguration.SetXFrameOffset(newXOffset: integer); | |
begin | |
if (newXOffset <= 490) and (newXOffset >= 0) then | |
begin | |
fXFrameOffset := newXOffset; | |
bDirty := True; | |
end; | |
end; | |
procedure TConfiguration.SetYFrameOffset(newYOffset: integer); | |
begin | |
if (newYOffset <= 490) and (newYOffset >= 0) then | |
begin | |
fYFrameOffset := newYOffset; | |
bDirty := True; | |
end; | |
end; | |
function TConfiguration.AnalogToDigitalValue(chIndex: integer; analogVal: double): integer; | |
begin | |
Result := Round(2048 * (analogVal - PrefixToFactor(fChPrefixes[chIndex]) * fChOffsets[chIndex])/(fChConvFactors[chIndex] | |
* FullScaleToVal(fChInputRanges[chIndex]))); | |
end; | |
procedure TConfiguration.CopyTo(var configRecord: TConfigRecord); | |
var i: integer; | |
begin | |
configRecord.XFrameOffset := fXFrameOffset; | |
configRecord.YFrameOffset := fYFrameOffset; | |
configRecord.FrameWidth := fFrameWidth; | |
configRecord.FrameHeight := fFrameHeight; | |
configRecord.PixelClock := fPixelClock; | |
for i := 0 to 3 do | |
begin | |
configRecord.ChConvFactors[i] := fChConvFactors[i]; | |
configRecord.ChDataPtsPerFrames[i] := fChDataPtsPerFrames[i]; | |
configRecord.ChEnabled[i] := fChEnabled[i]; | |
configRecord.ChInputRanges[i] := fChInputRanges[i]; | |
configRecord.ChNames[i] := fChNames[i]; | |
configRecord.ChOffsets[i] := fChOffsets[i]; | |
configRecord.ChPrefixes[i] := fChPrefixes[i]; | |
configRecord.ChUnits[i] := fChUnits[i]; | |
end; | |
end; | |
function TConfiguration.DigitalToAnalogValue(chIndex: integer; digitalVal: integer): double; | |
begin | |
Result := fChConvFactors[chIndex] * | |
FullScaleToVal(fChInputRanges[chIndex]) * (digitalVal / 2048) + | |
PrefixToFactor(fChPrefixes[chIndex]) * fChOffsets[chIndex]; | |
end; | |
const | |
sFrame = 'Frame'; | |
sOptions = 'Options'; | |
sXFrameOffset = 'X Frame Offset'; | |
sYFrameOffset = 'Y Frame Offset'; | |
sFrameWidth = 'Frame Width'; | |
sFrameHeight = 'Frame Height'; | |
sPixelClock = 'Pixel Clock'; | |
sChannel = 'Channel '; | |
sChConvFactors = 'Conv Factor'; | |
sChDataPtsPerFrames = 'Data Pts Per Frame'; | |
sChEnabled = 'Enabled'; | |
sChInputRanges = 'Input Range'; | |
sChNames = 'Name'; | |
sChOffsets = 'Offset'; | |
sChPrefixes = 'Prefix'; | |
sChUnits = 'Unit'; | |
procedure TConfiguration.OpenConfiguration(const fname: string); | |
var configIni: TIniFile; | |
i: integer; | |
begin | |
configIni := TIniFile.Create(fname); | |
try | |
with configIni do | |
begin | |
fXFrameOffset := ReadInteger(sFrame, sXFrameOffset, 0); | |
fYFrameOffset := ReadInteger(sFrame, sYFrameOffset, 0); | |
fFrameWidth := ReadInteger(sFrame, sFrameWidth, 500); | |
fFrameHeight := ReadInteger(sFrame, sFrameHeight, 500); | |
fPixelClock := ReadInteger(sFrame, sPixelClock, 16); {1.25 MHz} | |
for i := 1 to 4 do | |
begin | |
fChConvFactors[i-1] := ReadFloat(sChannel + IntToStr(i), sChConvFactors, 1); | |
fChDataPtsPerFrames[i-1] := ReadInteger(sChannel + IntToStr(i), sChDataPtsPerFrames, 100); | |
fChEnabled[i-1] := ReadBool(sChannel + IntToStr(i), sChEnabled, True); | |
fChInputRanges[i-1] := TFullScaleVal(ReadInteger(sChannel + IntToStr(i), sChInputRanges, 0)); | |
fChNames[i-1] := ReadString(sChannel + IntToStr(i), sChNames, sChannel + IntToStr(i)); | |
fChOffsets[i-1] := ReadFloat(sChannel + IntToStr(i), sChOffsets, 0); | |
fChPrefixes[i-1] := TPrefix(ReadInteger(sChannel + IntToStr(i), sChPrefixes, 0)); | |
fChUnits[i-1] := ReadString(sChannel + IntToStr(i), sChUnits, 'V'); | |
end; | |
end; | |
bDirty := False; | |
sConfigName := fname; | |
finally | |
configIni.Free; | |
end; | |
end; | |
procedure TConfiguration.RestoreFrom(const configRecord: TConfigRecord); | |
var i: integer; | |
begin | |
fXFrameOffset := configRecord.XFrameOffset; | |
fYFrameOffset := configRecord.YFrameOffset; | |
fFrameWidth := configRecord.FrameWidth; | |
fFrameHeight := configRecord.FrameHeight; | |
fPixelClock := configRecord.PixelClock; | |
for i := 0 to 3 do | |
begin | |
fChConvFactors[i] := configRecord.ChConvFactors[i]; | |
fChDataPtsPerFrames[i] := configRecord.ChDataPtsPerFrames[i]; | |
fChEnabled[i] := configRecord.ChEnabled[i]; | |
fChInputRanges[i] := configRecord.ChInputRanges[i]; | |
fChNames[i] := configRecord.ChNames[i]; | |
fChOffsets[i] := configRecord.ChOffsets[i]; | |
fChPrefixes[i] := configRecord.ChPrefixes[i]; | |
fChUnits[i] := configRecord.ChUnits[i]; | |
end; | |
end; | |
procedure TConfiguration.SaveConfiguration(const fname: string); | |
var configIni: TIniFile; | |
i: integer; | |
begin | |
if fname = '' then Exit; | |
configIni := TIniFile.Create(fname); | |
try | |
with configIni do | |
begin | |
WriteInteger(sFrame, sXFrameOffset, fXFrameOffset); | |
WriteInteger(sFrame, sYFrameOffset, fYFrameOffset); | |
WriteInteger(sFrame, sFrameWidth, fFrameWidth); | |
WriteInteger(sFrame, sFrameHeight, fFrameHeight); | |
WriteInteger(sFrame, sPixelClock, fPixelClock); | |
for i := 1 to 4 do | |
begin | |
WriteFloat(sChannel + IntToStr(i), sChConvFactors, ChConvFactors[i-1]); | |
WriteInteger(sChannel + IntToStr(i), sChDataPtsPerFrames, fChDataPtsPerFrames[i-1]); | |
WriteBool(sChannel + IntToStr(i), sChEnabled, fChEnabled[i-1]); | |
WriteInteger(sChannel + IntToStr(i), sChInputRanges, Integer(fChInputRanges[i-1])); | |
WriteString(sChannel + IntToStr(i), sChNames, fChNames[i-1]); | |
WriteFloat(sChannel + IntToStr(i), sChOffsets, fChOffsets[i-1]); | |
WriteInteger(sChannel + IntToStr(i), sChPrefixes, Integer(fChPrefixes[i-1])); | |
WriteString(sChannel + IntToStr(i), sChUnits, fChUnits[i-1]); | |
end; | |
end; | |
bDirty := False; | |
sConfigName := fname; | |
finally | |
configIni.Free; | |
end; | |
end; | |
constructor TConfiguration.Create; | |
begin | |
DefaultConfig; | |
end; | |
{*********************************** MPFile ***********************************} | |
function TMPFile.DefaultFileName(const fileDir: string): string; | |
var i: integer; | |
begin | |
i := 0; | |
repeat | |
i := i + 1; | |
Result := FormatDateTime('yymmdd', Now) + '_' + Format('%.3d', [i]) + '.MPD'; | |
until not FileExists(ExcludeTrailingBackslash(fileDir) + '\' + Result); | |
end; | |
procedure TMPFile.Close(sComments: string); | |
var ps: TpPropSpecArray; | |
pv: TpPropVariantArray; | |
const sPropName: WideString = 'Comments'; | |
begin | |
if bDirty then | |
begin | |
if Length(sComments) > 0 then | |
begin | |
ps := nil; pv := nil; | |
try | |
GetMem(ps, SizeOf(TPropSpec)); | |
GetMem(pv, SizeOf(TPropVariant)); | |
ps^[0].ulKind := PRSPEC_LPWSTR; | |
ps^[0].lpwstr := PWideChar(sPropName); | |
{ pv^[0].vt := VT_LPSTR; | |
pv^[0].pszVal := PChar(@sComments[1]);} | |
pv^[0].vt := VT_LPWSTR; | |
pv^[0].pwszVal := StringToOLEStr(sComments); | |
{ pv^[0].vt := VT_LPSTR; | |
pv^[0].pszVal := @(PChar(sComments)^);} | |
OleCheck(fPropertyStorage.WriteMultiple(1, @ps[0], @pv[0], 2)); | |
finally | |
if ps <> nil then Freemem(ps); | |
if pv <> nil then Freemem(pv); | |
end; | |
end; | |
OleCheck(fPropertyStorage.Commit(STGC_DEFAULT)); | |
end; | |
fPropertyStorage := nil; | |
fPropertySetStorage := nil; | |
if streams[0] <> nil then streams[0] := nil; | |
if streams[1] <> nil then streams[0] := nil; | |
if streams[2] <> nil then streams[0] := nil; | |
if streams[3] <> nil then streams[0] := nil; | |
rootStorage := nil; | |
if not bDirty then DeleteFile(filename); | |
end; | |
const | |
OFLAGS = STGM_DIRECT or STGM_READWRITE or STGM_CREATE or STGM_SHARE_EXCLUSIVE; | |
procedure TMPFile.NewFile(const sNewFile: string); | |
var hr : HResult; | |
ws: Widestring; | |
begin | |
ws := sNewFile; | |
hr := StgCreateDocFile(PWideChar(ws), OFLAGS, 0, rootStorage); | |
if not Succeeded(hr) then | |
begin | |
MessageDlg(FileErrToStr(StgErrToFileErr(hr)), mtError, [mbOK], 0); | |
{possible cause: bad file name; try default file name} | |
ws := ExcludeTrailingBackslash(ExtractFilePath(Filename)) + '\' + | |
DefaultFileName(ExcludeTrailingBackslash(ExtractFilePath(Filename))); | |
hr := StgCreateDocFile(PWideChar(ws), OFLAGS, 0, rootStorage); | |
end; | |
if Succeeded(hr) then | |
begin | |
sFilename := sNewFile; | |
fPropertySetStorage := rootStorage as IPropertySetStorage; | |
if not Succeeded(fPropertySetStorage.Create(FMTID_User_Defined_Properties, | |
FMTID_User_Defined_Properties, PROPSETFLAG_DEFAULT, OFLAGS, fPropertyStorage)) then | |
MessageDlg('Cannot open property set', mtError, [mbOK], 0); | |
rootStorage.SetClass(GUID_MPD); | |
end; | |
end; | |
function BooleanToString(abool: Boolean): string; | |
begin | |
if abool then Result := 'True' else Result := 'False'; | |
end; | |
function ScanModeToString(smode: TScanMode): string; | |
begin | |
case smode of | |
SM_MOVIE: Result := 'Movie'; | |
SM_STACK: Result := 'Image Stack'; | |
SM_STACKMOVIE: Result := 'Image Stack Movie'; | |
SM_LINESCAN: Result := 'Line Scan'; | |
SM_REPEAT_LINESCAN: Result := 'Repeat Line Scan'; | |
else Result := ''; | |
end | |
end; | |
procedure TMPFile.SetProperties(const config: TConfiguration); | |
const sPropNames: array[0..29] of string = ('Scan Mode', 'Stack Count', 'z- Interval', 'X Frame Offset', 'Y Frame Offset', | |
'Frame Width', 'Frame Height', 'Pixel Clock', | |
'Channel name (1)', 'Enabled (1)', 'Input Range (1)', | |
'Channel name (2)', 'Enabled (2)', 'Input Range (2)', | |
'Channel name (3)', 'Enabled (3)', 'Input Range (3)', 'Channel Unit (3)', | |
'Channel Prefix (3)', 'Conversion factor (3)', 'Offset (3)', 'Data Points Per Frame (3)', | |
'Channel name (4)', 'Enabled (4)', 'Input Range (4)', 'Channel Unit (4)', | |
'Channel Prefix (4)', 'Conversion factor (4)', 'Offset (4)', 'Data Points Per Frame (4)'); | |
var i, j : integer; | |
sPropValues: array[0..29] of string; | |
ps: TpPropSpecArray; | |
pv: TpPropVariantArray; | |
wc: Widestring; | |
begin | |
with config do | |
begin | |
sPropValues[0] := ScanModeToString(ScanMode); | |
sPropValues[1] := IntToStr(stackCount); | |
sPropValues[2] := FloatToStr(zInterval); | |
sPropValues[3] := IntToStr(XFrameOffset); | |
sPropValues[4] := IntToStr(YFrameOffset); | |
sPropValues[5] := IntToStr(FrameWidth); | |
sPropValues[6] := IntToStr(FrameHeight); | |
sPropValues[7] := IntToStr(PixelClock); | |
j := 8; | |
for i := 0 to 3 do | |
begin | |
sPropValues[j] := ChNames[i]; j := j + 1; | |
sPropValues[j] := BooleanToString(ChEnabled[i]); j := j + 1; | |
sPropValues[j] := InputRangeToString(ChInputRanges[i]); j := j + 1; | |
if i > 1 then | |
begin | |
sPropValues[j] := ChUnits[i]; j := j + 1; | |
sPropValues[j] := PrefixToString(ChPrefixes[i]); j := j + 1; | |
sPropValues[j] := FloatToStr(ChConvFactors[i]); j := j + 1; | |
sPropValues[j] := FloatToStr(ChOffsets[i]); j := j + 1; | |
sPropValues[j] := IntToStr(ChDataPtsPerFrames[i]); j := j + 1; | |
end; | |
end; | |
end; | |
ps := nil; pv := nil; | |
try | |
GetMem(ps, 30 * SizeOf(TPropSpec)); | |
GetMem(pv, 30 * SizeOf(TPropVariant)); | |
for i := 0 to 29 do | |
begin | |
ps^[i].ulKind := PRSPEC_LPWSTR; | |
ps^[i].lpwstr := StringToOLEStr(sPropNames[i]); | |
{ps^[i].lpwstr := @(StringToWideChar(sPropNames[i], @sWideChar, Length(sPropNames[i]) + 1)^);} | |
{pv^[i].vt := VT_LPSTR; | |
pv^[i].pszVal := PChar(@sPropValues[i][1]);} | |
pv^[i].vt := VT_LPWSTR; | |
pv^[i].pwszVal := StringToOLEStr(sPropValues[i]); | |
{ pv^[i].vt := VT_LPSTR; | |
pv^[i].pszVal := @(PChar(sPropValues[i])^);} | |
end; | |
OleCheck(fPropertyStorage.WriteMultiple(30, @ps[0], @pv[0], 2)); | |
finally | |
if ps <> nil then Freemem(ps); | |
if pv <> nil then Freemem(pv); | |
end; | |
{creates the data streams} | |
for i := 0 to 3 do | |
if config.ChEnabled[i] then | |
begin | |
wc := 'Ch'+IntToStr(i); | |
OLECheck(rootStorage.CreateStream(@wc, OFLAGS, 0, 0, streams[i])); | |
end; | |
end; | |
function TMPFile.Write(streamIndex: integer; var data; cbytes: integer): boolean; | |
var cbWritten: longint; | |
begin | |
try | |
if (streamIndex >= 0) and (streamIndex <= 3) then | |
if streams[streamIndex] <> nil then | |
OleCheck(streams[streamIndex].Write(@data, cbytes, @cbWritten)); | |
Result := True; | |
except | |
Result := False; | |
end; | |
end; | |
constructor TMPFile.Create(const sInitialDir: string); | |
begin | |
sFileName := ExcludeTrailingBackslash(sInitialDir) + '\' + DefaultFileName(sInitialDir); | |
NewFile(sFileName); | |
end; | |
function StgErrToFileErr(hr: HResult): TFileErr; | |
begin | |
{if integer(hr) = STG_E_INVALIDFUNCTION then | |
else} if integer(hr) = STG_E_FILENOTFOUND then | |
Result := feCannotFindFile | |
else if integer(hr) = STG_E_PATHNOTFOUND then | |
Result := fePathNotFound | |
else if integer(hr) = STG_E_TOOMANYOPENFILES then | |
Result := feTooManyFilesOpened | |
else if integer(hr) = STG_E_ACCESSDENIED then | |
Result := feAccessDenied | |
{ else if integer(hr) = STG_E_INVALIDHANDLE then | |
Result := ;} | |
else if integer(hr) = STG_E_INSUFFICIENTMEMORY then | |
Result := feOutOfMemory | |
else if integer(hr) = STG_E_INVALIDPOINTER then | |
Result := feBadData | |
{ else if integer(hr) = STG_E_NOMOREFILES then | |
Result := ;} | |
else if integer(hr) = STG_E_DISKISWRITEPROTECTED then | |
Result := feCannotReadFile | |
else if integer(hr) = STG_E_SEEKERROR then | |
Result := feCannotReadFile | |
else if integer(hr) = STG_E_WRITEFAULT then | |
Result := feUnexpectedEOF | |
else if integer(hr) = STG_E_READFAULT then | |
Result := feCannotReadFile | |
else if integer(hr) = STG_E_SHAREVIOLATION then | |
Result := feShareViolation | |
{ else if integer(hr) = STG_E_LOCKVIOLATION then | |
Result := ; | |
else if integer(hr) = STG_E_FILEALREADYEXISTS then | |
Result := ; | |
else if integer(hr) = STG_E_INVALIDPARAMETER then | |
Result := ;} | |
else if integer(hr) = STG_E_MEDIUMFULL then | |
Result := feDiskFull | |
{ else if integer(hr) = STG_E_ABNORMALAPIEXIT then | |
Result := ; | |
else if integer(hr) = STG_E_INVALIDHEADER then | |
Result := ;} | |
else if integer(hr) = STG_E_INVALIDNAME then | |
Result := feInvalidName | |
else if integer(hr) = STG_E_UNKNOWN then | |
Result := feUnknownError | |
{ else if integer(hr) = STG_E_UNIMPLEMENTEDFUNCTION then | |
Result := ; | |
else if integer(hr) = STG_E_INVALIDFLAG then | |
Result := ;} | |
else | |
Result := feUnknownError; | |
end; | |
function PointStrictlyInRect(const aPt: TPoint; aRect: TRect): boolean; | |
begin | |
NormalizeRect(aRect); | |
if (aPt.X >= aRect.Left) and (aPt.X <= aRect.Right) and | |
(aPt.Y >= aRect.Top) and (aPt.Y <= aRect.Bottom) then | |
Result := True | |
else | |
Result := False; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ************************************************************************ // | |
{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers. | |
{$WARN SYMBOL_PLATFORM OFF} | |
{$WRITEABLECONST ON} | |
{$VARPROPSETTER ON} | |
interface | |
uses Windows, ActiveX, Classes, Graphics, StdVCL, Variants; | |
// *********************************************************************// | |
// GUIDS declared in the TypeLibrary. Following prefixes are used: | |
// Type Libraries : LIBID_xxxx | |
// CoClasses : CLASS_xxxx | |
// DISPInterfaces : DIID_xxxx | |
// Non-DISP interfaces: IID_xxxx | |
// *********************************************************************// | |
const | |
// TypeLibrary Major and minor versions | |
MPSCAN_PCMajorVersion = 1; | |
MPSCAN_PCMinorVersion = 0; | |
LIBID_MPSCAN_PC: TGUID = '{1961FB4B-89F1-4E35-8884-1B28F8244C7A}'; | |
IID_IMultiphoton: TGUID = '{528196B3-544E-4C91-A526-2FE2AA21333D}'; | |
IID_IMPLaserShutter: TGUID = '{637AD17F-5D45-40AE-9759-2CCD019F6CD2}'; | |
DIID_IMultiphotonEvents: TGUID = '{7E98D2E3-6D6C-4272-A726-D0E083CC2367}'; | |
CLASS_MultiPhoton: TGUID = '{77B5B174-06ED-48B8-AF6E-E1832F70217F}'; | |
CLASS_MPLaserShutter: TGUID = '{2B3B5753-7DB9-4F42-A922-9FA646C71138}'; | |
IID_IMPXYTable: TGUID = '{C66DFBD1-03E6-4E52-84E9-CA6F0C64E6F9}'; | |
CLASS_MPXYTable: TGUID = '{1527F79A-6579-4DA7-AEB1-E0EA516463FD}'; | |
IID_IMPZStepper: TGUID = '{C6A2E09D-B249-4564-9DC8-5FBE10FCB8EF}'; | |
CLASS_MPZStepper: TGUID = '{32C1BEE8-52F1-45DC-82E8-3955F5CFF9C0}'; | |
IID_IMatlab: TGUID = '{AA58FC68-0FA8-4327-8B53-888ABAD56938}'; | |
CLASS_MPMatlab: TGUID = '{04CEF2DA-92AF-4FFF-B178-9B776A60357C}'; | |
IID_IMPCounter: TGUID = '{A69A0D54-D5DD-4EF3-A1CC-6950148116B6}'; | |
CLASS_MPCounter: TGUID = '{E76CE279-58CC-42B4-9DD9-742B02A3D5C4}'; | |
IID_IMPLaserControl: TGUID = '{A4CE28BD-F4AB-4395-8A32-A8C86FD9B56F}'; | |
CLASS_MPLaserControl: TGUID = '{0FEC246A-0D56-417D-A21A-E26A4651E117}'; | |
type | |
// *********************************************************************// | |
// Forward declaration of types defined in TypeLibrary | |
// *********************************************************************// | |
IMultiphoton = interface; | |
IMultiphotonDisp = dispinterface; | |
IMPLaserShutter = interface; | |
IMPLaserShutterDisp = dispinterface; | |
IMultiphotonEvents = dispinterface; | |
IMPXYTable = interface; | |
IMPXYTableDisp = dispinterface; | |
IMPZStepper = interface; | |
IMPZStepperDisp = dispinterface; | |
IMatlab = interface; | |
IMatlabDisp = dispinterface; | |
IMPCounter = interface; | |
IMPCounterDisp = dispinterface; | |
IMPLaserControl = interface; | |
IMPLaserControlDisp = dispinterface; | |
// *********************************************************************// | |
// Declaration of CoClasses defined in Type Library | |
// (NOTE: Here we map each CoClass to its Default Interface) | |
// *********************************************************************// | |
MultiPhoton = IMultiphoton; | |
MPLaserShutter = IMPLaserShutter; | |
MPXYTable = IMPXYTable; | |
MPZStepper = IMPZStepper; | |
MPMatlab = IMatlab; | |
MPCounter = IMPCounter; | |
MPLaserControl = IMPLaserControl; | |
// *********************************************************************// | |
// Declaration of structures, unions and aliases. | |
// *********************************************************************// | |
PWideString1 = ^WideString; | |
// *********************************************************************// | |
// Interface: IMultiphoton | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {528196B3-544E-4C91-A526-2FE2AA21333D} | |
// *********************************************************************// | |
IMultiphoton = interface(IDispatch) | |
['{528196B3-544E-4C91-A526-2FE2AA21333D}'] | |
procedure AddFileProperty(const propname: WideString; const propvalue: WideString); safecall; | |
procedure Set_FileComments(const Param1: WideString); safecall; | |
function Get_Laser_Shutter: MPLaserShutter; safecall; | |
procedure LoadConfiguration(const configName: WideString); safecall; | |
procedure SetLaserBeamTo(X: Integer; Y: Integer); safecall; | |
procedure StartDigitalStim; safecall; | |
procedure StopDigitalStimulation; safecall; | |
procedure StartScan; safecall; | |
procedure StopScan; safecall; | |
procedure StartStreaming; safecall; | |
procedure StopStreaming; safecall; | |
procedure SetDigitalBit(digitalline: Integer; digitalvalue: Integer); safecall; | |
procedure NewDataFile(const filename: WideString); safecall; | |
procedure Wait(mscount: Integer); safecall; | |
function Get_LastFrameIndex: Integer; safecall; | |
function Get_matlab: MPMatlab; safecall; | |
function Get_XY_Table: MPXYTable; safecall; | |
function Get_Z_Stepper: MPZStepper; safecall; | |
function Get_Scanning: Integer; safecall; | |
procedure DoEvents; safecall; | |
function Get_YScanOffset: Integer; safecall; | |
procedure Set_YScanOffset(Value: Integer); safecall; | |
procedure EndScript; safecall; | |
function Get_GPCTR0: MPCounter; safecall; | |
function Get_GPCTR1: MPCounter; safecall; | |
function Get_Laser: MPLaserControl; safecall; | |
procedure LoadDigitalStim(const digitalstimFile: WideString); safecall; | |
procedure WriteMessage(const Param1: WideString); safecall; | |
property FileComments: WideString write Set_FileComments; | |
property Laser_Shutter: MPLaserShutter read Get_Laser_Shutter; | |
property LastFrameIndex: Integer read Get_LastFrameIndex; | |
property matlab: MPMatlab read Get_matlab; | |
property XY_Table: MPXYTable read Get_XY_Table; | |
property Z_Stepper: MPZStepper read Get_Z_Stepper; | |
property Scanning: Integer read Get_Scanning; | |
property YScanOffset: Integer read Get_YScanOffset write Set_YScanOffset; | |
property GPCTR0: MPCounter read Get_GPCTR0; | |
property GPCTR1: MPCounter read Get_GPCTR1; | |
property Laser: MPLaserControl read Get_Laser; | |
end; | |
// *********************************************************************// | |
// DispIntf: IMultiphotonDisp | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {528196B3-544E-4C91-A526-2FE2AA21333D} | |
// *********************************************************************// | |
IMultiphotonDisp = dispinterface | |
['{528196B3-544E-4C91-A526-2FE2AA21333D}'] | |
procedure AddFileProperty(const propname: WideString; const propvalue: WideString); dispid 1; | |
property FileComments: WideString writeonly dispid 3; | |
property Laser_Shutter: MPLaserShutter readonly dispid 4; | |
procedure LoadConfiguration(const configName: WideString); dispid 6; | |
procedure SetLaserBeamTo(X: Integer; Y: Integer); dispid 8; | |
procedure StartDigitalStim; dispid 9; | |
procedure StopDigitalStimulation; dispid 10; | |
procedure StartScan; dispid 11; | |
procedure StopScan; dispid 12; | |
procedure StartStreaming; dispid 13; | |
procedure StopStreaming; dispid 14; | |
procedure SetDigitalBit(digitalline: Integer; digitalvalue: Integer); dispid 15; | |
procedure NewDataFile(const filename: WideString); dispid 16; | |
procedure Wait(mscount: Integer); dispid 17; | |
property LastFrameIndex: Integer readonly dispid 25; | |
property matlab: MPMatlab readonly dispid 5; | |
property XY_Table: MPXYTable readonly dispid 18; | |
property Z_Stepper: MPZStepper readonly dispid 19; | |
property Scanning: Integer readonly dispid 7; | |
procedure DoEvents; dispid 20; | |
property YScanOffset: Integer dispid 21; | |
procedure EndScript; dispid 22; | |
property GPCTR0: MPCounter readonly dispid 26; | |
property GPCTR1: MPCounter readonly dispid 27; | |
property Laser: MPLaserControl readonly dispid 28; | |
procedure LoadDigitalStim(const digitalstimFile: WideString); dispid 201; | |
procedure WriteMessage(const Param1: WideString); dispid 202; | |
end; | |
// *********************************************************************// | |
// Interface: IMPLaserShutter | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {637AD17F-5D45-40AE-9759-2CCD019F6CD2} | |
// *********************************************************************// | |
IMPLaserShutter = interface(IDispatch) | |
['{637AD17F-5D45-40AE-9759-2CCD019F6CD2}'] | |
procedure Close; safecall; | |
procedure Open; safecall; | |
end; | |
// *********************************************************************// | |
// DispIntf: IMPLaserShutterDisp | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {637AD17F-5D45-40AE-9759-2CCD019F6CD2} | |
// *********************************************************************// | |
IMPLaserShutterDisp = dispinterface | |
['{637AD17F-5D45-40AE-9759-2CCD019F6CD2}'] | |
procedure Close; dispid 1; | |
procedure Open; dispid 2; | |
end; | |
// *********************************************************************// | |
// DispIntf: IMultiphotonEvents | |
// Flags: (4096) Dispatchable | |
// GUID: {7E98D2E3-6D6C-4272-A726-D0E083CC2367} | |
// *********************************************************************// | |
IMultiphotonEvents = dispinterface | |
['{7E98D2E3-6D6C-4272-A726-D0E083CC2367}'] | |
procedure OnBtn1Clicked(const mpapp: IMultiphoton); dispid 1; | |
procedure OnBtn2Clicked(const mpapp: IMultiphoton); dispid 2; | |
procedure OnBtn3Clicked(const mpapp: IMultiphoton); dispid 3; | |
end; | |
// *********************************************************************// | |
// Interface: IMPXYTable | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {C66DFBD1-03E6-4E52-84E9-CA6F0C64E6F9} | |
// *********************************************************************// | |
IMPXYTable = interface(IDispatch) | |
['{C66DFBD1-03E6-4E52-84E9-CA6F0C64E6F9}'] | |
procedure MoveToXY(X: Integer; Y: Integer); safecall; | |
procedure ShiftByXY(deltaX: Integer; deltaY: Integer); safecall; | |
function Get_XPosition: Integer; safecall; | |
function Get_YPosition: Integer; safecall; | |
procedure XYCommand(const sCommand: WideString); safecall; | |
function Get_XYSpeed: Integer; safecall; | |
procedure Set_XYSpeed(Value: Integer); safecall; | |
procedure GalilCall(const sCommand: WideString); safecall; | |
procedure GalilWaitForMotionComplete; safecall; | |
procedure sDMCCmd(const sCommand: WideString); safecall; | |
procedure sDMCWait(const sAxes: WideString); safecall; | |
procedure sSetDMCTimeout(timeout: Integer); safecall; | |
function Get_Reply: WideString; safecall; | |
procedure Set_Reply(const Value: WideString); safecall; | |
property XPosition: Integer read Get_XPosition; | |
property YPosition: Integer read Get_YPosition; | |
property XYSpeed: Integer read Get_XYSpeed write Set_XYSpeed; | |
property Reply: WideString read Get_Reply write Set_Reply; | |
end; | |
// *********************************************************************// | |
// DispIntf: IMPXYTableDisp | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {C66DFBD1-03E6-4E52-84E9-CA6F0C64E6F9} | |
// *********************************************************************// | |
IMPXYTableDisp = dispinterface | |
['{C66DFBD1-03E6-4E52-84E9-CA6F0C64E6F9}'] | |
procedure MoveToXY(X: Integer; Y: Integer); dispid 1; | |
procedure ShiftByXY(deltaX: Integer; deltaY: Integer); dispid 3; | |
property XPosition: Integer readonly dispid 7; | |
property YPosition: Integer readonly dispid 8; | |
procedure XYCommand(const sCommand: WideString); dispid 2; | |
property XYSpeed: Integer dispid 4; | |
procedure GalilCall(const sCommand: WideString); dispid 201; | |
procedure GalilWaitForMotionComplete; dispid 202; | |
procedure sDMCCmd(const sCommand: WideString); dispid 203; | |
procedure sDMCWait(const sAxes: WideString); dispid 204; | |
procedure sSetDMCTimeout(timeout: Integer); dispid 205; | |
property Reply: WideString dispid 206; | |
end; | |
// *********************************************************************// | |
// Interface: IMPZStepper | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {C6A2E09D-B249-4564-9DC8-5FBE10FCB8EF} | |
// *********************************************************************// | |
IMPZStepper = interface(IDispatch) | |
['{C6A2E09D-B249-4564-9DC8-5FBE10FCB8EF}'] | |
procedure MoveTo(z: Double); safecall; | |
procedure ShiftByZ(deltaZ: Double); safecall; | |
function Get_ZPosition: Double; safecall; | |
function Get_ZSpeed: Double; safecall; | |
procedure Set_ZSpeed(Value: Double); safecall; | |
property ZPosition: Double read Get_ZPosition; | |
property ZSpeed: Double read Get_ZSpeed write Set_ZSpeed; | |
end; | |
// *********************************************************************// | |
// DispIntf: IMPZStepperDisp | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {C6A2E09D-B249-4564-9DC8-5FBE10FCB8EF} | |
// *********************************************************************// | |
IMPZStepperDisp = dispinterface | |
['{C6A2E09D-B249-4564-9DC8-5FBE10FCB8EF}'] | |
procedure MoveTo(z: Double); dispid 2; | |
procedure ShiftByZ(deltaZ: Double); dispid 3; | |
property ZPosition: Double readonly dispid 1; | |
property ZSpeed: Double dispid 4; | |
end; | |
// *********************************************************************// | |
// Interface: IMatlab | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {AA58FC68-0FA8-4327-8B53-888ABAD56938} | |
// *********************************************************************// | |
IMatlab = interface(IDispatch) | |
['{AA58FC68-0FA8-4327-8B53-888ABAD56938}'] | |
procedure Start; safecall; | |
procedure PutROI(ROIIndex: Integer; const ArrayName: WideString); safecall; | |
procedure Execute(const mcommand: WideString); safecall; | |
end; | |
// *********************************************************************// | |
// DispIntf: IMatlabDisp | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {AA58FC68-0FA8-4327-8B53-888ABAD56938} | |
// *********************************************************************// | |
IMatlabDisp = dispinterface | |
['{AA58FC68-0FA8-4327-8B53-888ABAD56938}'] | |
procedure Start; dispid 1; | |
procedure PutROI(ROIIndex: Integer; const ArrayName: WideString); dispid 2; | |
procedure Execute(const mcommand: WideString); dispid 3; | |
end; | |
// *********************************************************************// | |
// Interface: IMPCounter | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {A69A0D54-D5DD-4EF3-A1CC-6950148116B6} | |
// *********************************************************************// | |
IMPCounter = interface(IDispatch) | |
['{A69A0D54-D5DD-4EF3-A1CC-6950148116B6}'] | |
procedure Change_Parameter(paramID: Integer; paramValue: Integer); safecall; | |
procedure Control(action: Integer); safecall; | |
procedure Set_Application(application: Integer); safecall; | |
procedure Select_Signal(polarity: Integer); safecall; | |
procedure Set_Count_1(Param1: Integer); safecall; | |
procedure Set_Count_2(Param1: Integer); safecall; | |
procedure Reset; safecall; | |
procedure Start; safecall; | |
function Watch(entityID: Integer): Integer; safecall; | |
procedure Set_CounterIndex(Param1: Integer); safecall; | |
procedure Set_Count_3(Param1: Integer); safecall; | |
procedure Set_Count_4(Param1: Integer); safecall; | |
property Count_1: Integer write Set_Count_1; | |
property Count_2: Integer write Set_Count_2; | |
property CounterIndex: Integer write Set_CounterIndex; | |
property Count_3: Integer write Set_Count_3; | |
property Count_4: Integer write Set_Count_4; | |
end; | |
// *********************************************************************// | |
// DispIntf: IMPCounterDisp | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {A69A0D54-D5DD-4EF3-A1CC-6950148116B6} | |
// *********************************************************************// | |
IMPCounterDisp = dispinterface | |
['{A69A0D54-D5DD-4EF3-A1CC-6950148116B6}'] | |
procedure Change_Parameter(paramID: Integer; paramValue: Integer); dispid 1; | |
procedure Control(action: Integer); dispid 2; | |
procedure Set_Application(application: Integer); dispid 3; | |
procedure Select_Signal(polarity: Integer); dispid 4; | |
property Count_1: Integer writeonly dispid 5; | |
property Count_2: Integer writeonly dispid 6; | |
procedure Reset; dispid 7; | |
procedure Start; dispid 8; | |
function Watch(entityID: Integer): Integer; dispid 9; | |
property CounterIndex: Integer writeonly dispid 10; | |
property Count_3: Integer writeonly dispid 13; | |
property Count_4: Integer writeonly dispid 14; | |
end; | |
// *********************************************************************// | |
// Interface: IMPLaserControl | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {A4CE28BD-F4AB-4395-8A32-A8C86FD9B56F} | |
// *********************************************************************// | |
IMPLaserControl = interface(IDispatch) | |
['{A4CE28BD-F4AB-4395-8A32-A8C86FD9B56F}'] | |
function Get_Power: Integer; safecall; | |
procedure Set_Power(Value: Integer); safecall; | |
function Get_Wavelength: Integer; safecall; | |
procedure Set_Wavelength(Value: Integer); safecall; | |
property Power: Integer read Get_Power write Set_Power; | |
property Wavelength: Integer read Get_Wavelength write Set_Wavelength; | |
end; | |
// *********************************************************************// | |
// DispIntf: IMPLaserControlDisp | |
// Flags: (4416) Dual OleAutomation Dispatchable | |
// GUID: {A4CE28BD-F4AB-4395-8A32-A8C86FD9B56F} | |
// *********************************************************************// | |
IMPLaserControlDisp = dispinterface | |
['{A4CE28BD-F4AB-4395-8A32-A8C86FD9B56F}'] | |
property Power: Integer dispid 1; | |
property Wavelength: Integer dispid 2; | |
end; | |
// *********************************************************************// | |
// The Class CoMultiPhoton provides a Create and CreateRemote method to | |
// create instances of the default interface IMultiphoton exposed by | |
// the CoClass MultiPhoton. The functions are intended to be used by | |
// clients wishing to automate the CoClass objects exposed by the | |
// server of this typelibrary. | |
// *********************************************************************// | |
CoMultiPhoton = class | |
class function Create: IMultiphoton; | |
class function CreateRemote(const MachineName: string): IMultiphoton; | |
end; | |
// *********************************************************************// | |
// The Class CoMPLaserShutter provides a Create and CreateRemote method to | |
// create instances of the default interface IMPLaserShutter exposed by | |
// the CoClass MPLaserShutter. The functions are intended to be used by | |
// clients wishing to automate the CoClass objects exposed by the | |
// server of this typelibrary. | |
// *********************************************************************// | |
CoMPLaserShutter = class | |
class function Create: IMPLaserShutter; | |
class function CreateRemote(const MachineName: string): IMPLaserShutter; | |
end; | |
// *********************************************************************// | |
// The Class CoMPXYTable provides a Create and CreateRemote method to | |
// create instances of the default interface IMPXYTable exposed by | |
// the CoClass MPXYTable. The functions are intended to be used by | |
// clients wishing to automate the CoClass objects exposed by the | |
// server of this typelibrary. | |
// *********************************************************************// | |
CoMPXYTable = class | |
class function Create: IMPXYTable; | |
class function CreateRemote(const MachineName: string): IMPXYTable; | |
end; | |
// *********************************************************************// | |
// The Class CoMPZStepper provides a Create and CreateRemote method to | |
// create instances of the default interface IMPZStepper exposed by | |
// the CoClass MPZStepper. The functions are intended to be used by | |
// clients wishing to automate the CoClass objects exposed by the | |
// server of this typelibrary. | |
// *********************************************************************// | |
CoMPZStepper = class | |
class function Create: IMPZStepper; | |
class function CreateRemote(const MachineName: string): IMPZStepper; | |
end; | |
// *********************************************************************// | |
// The Class CoMPMatlab provides a Create and CreateRemote method to | |
// create instances of the default interface IMatlab exposed by | |
// the CoClass MPMatlab. The functions are intended to be used by | |
// clients wishing to automate the CoClass objects exposed by the | |
// server of this typelibrary. | |
// *********************************************************************// | |
CoMPMatlab = class | |
class function Create: IMatlab; | |
class function CreateRemote(const MachineName: string): IMatlab; | |
end; | |
// *********************************************************************// | |
// The Class CoMPCounter provides a Create and CreateRemote method to | |
// create instances of the default interface IMPCounter exposed by | |
// the CoClass MPCounter. The functions are intended to be used by | |
// clients wishing to automate the CoClass objects exposed by the | |
// server of this typelibrary. | |
// *********************************************************************// | |
CoMPCounter = class | |
class function Create: IMPCounter; | |
class function CreateRemote(const MachineName: string): IMPCounter; | |
end; | |
// *********************************************************************// | |
// The Class CoMPLaserControl provides a Create and CreateRemote method to | |
// create instances of the default interface IMPLaserControl exposed by | |
// the CoClass MPLaserControl. The functions are intended to be used by | |
// clients wishing to automate the CoClass objects exposed by the | |
// server of this typelibrary. | |
// *********************************************************************// | |
CoMPLaserControl = class | |
class function Create: IMPLaserControl; | |
class function CreateRemote(const MachineName: string): IMPLaserControl; | |
end; | |
implementation | |
uses ComObj; | |
class function CoMultiPhoton.Create: IMultiphoton; | |
begin | |
Result := CreateComObject(CLASS_MultiPhoton) as IMultiphoton; | |
end; | |
class function CoMultiPhoton.CreateRemote(const MachineName: string): IMultiphoton; | |
begin | |
Result := CreateRemoteComObject(MachineName, CLASS_MultiPhoton) as IMultiphoton; | |
end; | |
class function CoMPLaserShutter.Create: IMPLaserShutter; | |
begin | |
Result := CreateComObject(CLASS_MPLaserShutter) as IMPLaserShutter; | |
end; | |
class function CoMPLaserShutter.CreateRemote(const MachineName: string): IMPLaserShutter; | |
begin | |
Result := CreateRemoteComObject(MachineName, CLASS_MPLaserShutter) as IMPLaserShutter; | |
end; | |
class function CoMPXYTable.Create: IMPXYTable; | |
begin | |
Result := CreateComObject(CLASS_MPXYTable) as IMPXYTable; | |
end; | |
class function CoMPXYTable.CreateRemote(const MachineName: string): IMPXYTable; | |
begin | |
Result := CreateRemoteComObject(MachineName, CLASS_MPXYTable) as IMPXYTable; | |
end; | |
class function CoMPZStepper.Create: IMPZStepper; | |
begin | |
Result := CreateComObject(CLASS_MPZStepper) as IMPZStepper; | |
end; | |
class function CoMPZStepper.CreateRemote(const MachineName: string): IMPZStepper; | |
begin | |
Result := CreateRemoteComObject(MachineName, CLASS_MPZStepper) as IMPZStepper; | |
end; | |
class function CoMPMatlab.Create: IMatlab; | |
begin | |
Result := CreateComObject(CLASS_MPMatlab) as IMatlab; | |
end; | |
class function CoMPMatlab.CreateRemote(const MachineName: string): IMatlab; | |
begin | |
Result := CreateRemoteComObject(MachineName, CLASS_MPMatlab) as IMatlab; | |
end; | |
class function CoMPCounter.Create: IMPCounter; | |
begin | |
Result := CreateComObject(CLASS_MPCounter) as IMPCounter; | |
end; | |
class function CoMPCounter.CreateRemote(const MachineName: string): IMPCounter; | |
begin | |
Result := CreateRemoteComObject(MachineName, CLASS_MPCounter) as IMPCounter; | |
end; | |
class function CoMPLaserControl.Create: IMPLaserControl; | |
begin | |
Result := CreateComObject(CLASS_MPLaserControl) as IMPLaserControl; | |
end; | |
class function CoMPLaserControl.CreateRemote(const MachineName: string): IMPLaserControl; | |
begin | |
Result := CreateRemoteComObject(MachineName, CLASS_MPLaserControl) as IMPLaserControl; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
*************************************************************************** | |
NI-DAQ Header file for Borland Delphi (32-bit) | |
Copyright (C) National Instruments 2000. | |
*************************************************************************** | |
} | |
unit NIDAQ; | |
interface | |
uses Windows; | |
{ special types } | |
type | |
i8 = ShortInt; | |
type | |
u8 = Byte; | |
type | |
pi8 = PChar; | |
type | |
i16 = SmallInt; | |
type | |
u16 = Word; | |
type | |
pi16 = ^i16; | |
type | |
pu16 = ^u16; | |
type | |
i32 = LongInt; | |
type | |
u32 = Cardinal; | |
type | |
pi32 = ^i32; | |
type | |
pu32 = ^u32; | |
type | |
f32 = Single; | |
type | |
f64 = Double; | |
type | |
pf64 = ^f64; | |
type | |
nidaqStatus = i16; | |
const | |
nidaqdll = 'nidaq32.dll'; | |
{ NI-DAQ function prototypes } | |
function AI_Change_Parameter ( | |
slot: i16; | |
channel: i16; | |
paramID: u32; | |
paramValue: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_Check ( | |
slot: i16; | |
status: pi16; | |
value: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_Clear ( | |
slot: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_Configure ( | |
slot: i16; | |
chan: i16; | |
inputMode: i16; | |
inputRange: i16; | |
polarity: i16; | |
driveAIS: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_Mux_Config ( | |
slot: i16; | |
numMuxBrds: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_Read ( | |
slot: i16; | |
chan: i16; | |
gain: i16; | |
value: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_Setup ( | |
slot: i16; | |
chan: i16; | |
gain: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_VRead ( | |
slot: i16; | |
chan: i16; | |
gain: i16; | |
volts: pf64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_VScale ( | |
slot: i16; | |
chan: i16; | |
gain: i16; | |
gainAdjust: f64; | |
offset: f64; | |
reading: i16; | |
voltage: pf64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Align_DMA_Buffer ( | |
slot: i16; | |
resource: i16; | |
buffer: pi16; | |
cnt: u32; | |
bufSize: u32; | |
alignIndex: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AO_Calibrate ( | |
board: i16; | |
operation: i16; | |
EEPROMloc: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AO_Configure ( | |
slot: i16; | |
chan: i16; | |
outputPolarity: i16; | |
IntOrExtRef: i16; | |
refVoltage: f64; | |
updateMode: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AO_Change_Parameter ( | |
slot: i16; | |
channel: i16; | |
paramID: u32; | |
paramValue: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AO_Update ( | |
slot: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AO_VWrite ( | |
slot: i16; | |
chan: i16; | |
voltage: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AO_Write ( | |
slot: i16; | |
chan: i16; | |
value: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Calibrate_E_Series ( | |
deviceNumber: i16; | |
calOp: u32; | |
setOfCalConst: u32; | |
calRefVolts: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Calibrate_59xx ( | |
deviceNumber: i16; | |
operation: u32; | |
refVoltage: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Calibrate_DSA ( | |
deviceNumber: i16; | |
operation: u32; | |
refVoltage: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Config_Alarm_Deadband ( | |
slot: i16; | |
mode: i16; | |
chanStr: pi8; | |
trigLvl: f64; | |
deadbandWidth: f64; | |
handle: HWND; | |
alarmOnMsg: i16; | |
alarmOffMsg: i16; | |
callbackAddr: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Config_ATrig_Event_Message ( | |
slot: i16; | |
mode: i16; | |
chanStr: pi8; | |
trigLvl: f64; | |
winSize: f64; | |
trigSlope: i16; | |
skipCnt: u32; | |
preTrigScans: u32; | |
postTrigScans: u32; | |
handle: HWND; | |
msg: i16; | |
callBackAddr: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Config_DAQ_Event_Message ( | |
slot: i16; | |
mode: i16; | |
chanStr: pi8; | |
DAQEvent: i16; | |
trigVal0: i32; | |
trigVal1: i32; | |
skipCnt: u32; | |
preTrigScans: u32; | |
postTrigScans: u32; | |
handle: HWND; | |
msg: i16; | |
callBackAddr: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Configure_HW_Analog_Trigger ( | |
deviceNumber: i16; | |
onOrOff: u32; | |
lowValue: i32; | |
highValue: i32; | |
mode: u32; | |
trigSource: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_Config ( | |
slot: i16; | |
ctr: i16; | |
edgeMode: i16; | |
gateMode: i16; | |
outType: i16; | |
outPolarity: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_EvCount ( | |
slot: i16; | |
ctr: i16; | |
timebase: i16; | |
cont: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_EvRead ( | |
slot: i16; | |
ctr: i16; | |
overflow: pi16; | |
counts: pu16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_FOUT_Config ( | |
slot: i16; | |
FOUT: i16; | |
mode: i16; | |
timebase: i16; | |
division: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_Period ( | |
slot: i16; | |
ctr: i16; | |
timebase: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_Pulse ( | |
slot: i16; | |
ctr: i16; | |
timebase: i16; | |
delay: u16; | |
pulseWidth: u16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_Rate ( | |
freq: f64; | |
duty: f64; | |
timebase: pi16; | |
period1: pu16; | |
period2: pu16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_Reset ( | |
slot: i16; | |
ctr: i16; | |
outState: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_Restart ( | |
slot: i16; | |
ctr: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_Simul_Op ( | |
slot: i16; | |
numCtrs: i16; | |
ctrList: pi16; | |
mode: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_Square ( | |
slot: i16; | |
ctr: i16; | |
timebase: i16; | |
period1: u16; | |
period2: u16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_State ( | |
slot: i16; | |
ctr: i16; | |
outState: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function CTR_Stop ( | |
slot: i16; | |
ctr: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_Check ( | |
slot: i16; | |
progress: pi16; | |
retrieved: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_Clear ( | |
slot: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_Config ( | |
slot: i16; | |
startTrig: i16; | |
extConv: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_DB_Config ( | |
slot: i16; | |
dbMode: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_DB_HalfReady ( | |
slot: i16; | |
halfReady: pi16; | |
status: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_DB_Transfer ( | |
slot: i16; | |
hbuffer: pi16; | |
ptsTfr: pu32; | |
status: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_Monitor ( | |
slot: i16; | |
chan: i16; | |
seq: i16; | |
monitorCnt: u32; | |
monitorBuf: pi16; | |
newestIndex: pu32; | |
status: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_Op ( | |
slot: i16; | |
chan: i16; | |
gain: i16; | |
buffer: pi16; | |
cnt: u32; | |
sampleRate: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_Rate ( | |
rate: f64; | |
units: i16; | |
timebase: pi16; | |
sampleInt: pu16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_Start ( | |
slot: i16; | |
chan: i16; | |
gain: i16; | |
buffer: pi16; | |
cnt: u32; | |
timebase: i16; | |
sampInt: u16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_StopTrigger_Config ( | |
slot: i16; | |
preTrig: i16; | |
preTrigCnt: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_to_Disk ( | |
slot: i16; | |
chan: i16; | |
gain: i16; | |
fileName: pi8; | |
cnt: u32; | |
sampleRate: f64; | |
concat: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_VScale ( | |
slot: i16; | |
chan: i16; | |
gain: i16; | |
gainAdjust: f64; | |
offset: f64; | |
cnt: u32; | |
binArray: pi16; | |
voltArray: pf64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Block_Check ( | |
slot: i16; | |
grp: i16; | |
remaining: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Block_Clear ( | |
slot: i16; | |
grp: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Block_In ( | |
slot: i16; | |
grp: i16; | |
buffer: pi16; | |
cnt: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Block_Out ( | |
slot: i16; | |
grp: i16; | |
buffer: pi16; | |
cnt: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Block_PG_Config ( | |
slot: i16; | |
grp: i16; | |
PGmode: i16; | |
reqSource: i16; | |
timebase: i16; | |
interval: u16; | |
externalGate: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_DB_Config ( | |
slot: i16; | |
grp: i16; | |
DBMode: i16; | |
oldDataStop: i16; | |
partialTransfer: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_DB_HalfReady ( | |
slot: i16; | |
grp: i16; | |
halfReady: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_DB_Transfer ( | |
slot: i16; | |
grp: i16; | |
halfBuffer: pi16; | |
ptsTfr: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Grp_Config ( | |
slot: i16; | |
grp: i16; | |
grpsize: i16; | |
port: i16; | |
direction: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Grp_Mode ( | |
slot: i16; | |
grp: i16; | |
sigType: i16; | |
edge: i16; | |
reqpol: i16; | |
ackpol: i16; | |
settleTime: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Grp_Status ( | |
slot: i16; | |
grp: i16; | |
status: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_In_Grp ( | |
slot: i16; | |
grp: i16; | |
grp_pat: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_In_Line ( | |
slot: i16; | |
port: i16; | |
linenum: i16; | |
state: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_In_Port ( | |
slot: i16; | |
port: i16; | |
pattern: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Line_Config ( | |
slot: i16; | |
port: i16; | |
linenum: i16; | |
direction: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Out_Grp ( | |
slot: i16; | |
grp: i16; | |
grp_pat: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Out_Line ( | |
slot: i16; | |
port: i16; | |
linenum: i16; | |
state: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Out_Port ( | |
slot: i16; | |
port: i16; | |
pattern: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Prt_Config ( | |
slot: i16; | |
port: i16; | |
latch_mode: i16; | |
direction: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Prt_Status ( | |
slot: i16; | |
port: i16; | |
status: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_SCAN_Setup ( | |
slot: i16; | |
grp: i16; | |
numPorts: i16; | |
portList: pi16; | |
direction: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Get_DAQ_Device_Info ( | |
deviceNumber: i16; | |
infoType: u32; | |
infoVal: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Get_DAQ_Event ( | |
timeOut: u32; | |
handle: pi16; | |
msg: pi16; | |
wParam: pi16; | |
lParam: pi32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Get_NI_DAQ_Version ( | |
version: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function GPCTR_Config_Buffer ( | |
deviceNumber: i16; | |
gpCounterNumber: u32; | |
reserved: u32; | |
numPoints: u32; | |
buffer: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function GPCTR_Read_Buffer ( | |
deviceNumber: i16; | |
gpCounterNumber: u32; | |
readMode: u32; | |
readOffset: i32; | |
numPointsToRead: u32; | |
timeOut: f64; | |
numPointsRead: pu32; | |
buffer: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Line_Change_Attribute ( | |
deviceNumber: i16; | |
lineNumber: u32; | |
attribID: u32; | |
attribValue: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function GPCTR_Control ( | |
deviceNumber: i16; | |
gpCounterNumber: u32; | |
action: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function GPCTR_Set_Application ( | |
deviceNumber: i16; | |
gpCounterNumber: u32; | |
application: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function GPCTR_Watch ( | |
deviceNumber: i16; | |
gpCounterNumber: u32; | |
watchID: u32; | |
watchValue: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function ICTR_Read ( | |
slot: i16; | |
counter: i16; | |
cnt: pu16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function ICTR_Reset ( | |
slot: i16; | |
counter: i16; | |
state: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function ICTR_Setup ( | |
slot: i16; | |
counter: i16; | |
mode: i16; | |
cnt: u16; | |
binBCD: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Init_DA_Brds ( | |
slot: i16; | |
brdCode: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Lab_ISCAN_Check ( | |
slot: i16; | |
status: pi16; | |
retrieved: pu32; | |
finalScanOrder: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Lab_ISCAN_Op ( | |
slot: i16; | |
numChans: i16; | |
gain: i16; | |
buffer: pi16; | |
cnt: u32; | |
sampleRate: f64; | |
scanRate: f64; | |
finalScanOrder: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Lab_ISCAN_Start ( | |
slot: i16; | |
numChans: i16; | |
gain: i16; | |
buffer: pi16; | |
cnt: u32; | |
timebase: i16; | |
sampleInt: u16; | |
scanInt: u16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Lab_ISCAN_to_Disk ( | |
slot: i16; | |
numChans: i16; | |
gain: i16; | |
fileName: pi8; | |
cnt: u32; | |
sampleRate: f64; | |
scanRate: f64; | |
concat: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function LPM16_Calibrate ( | |
slot: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function MIO_Config ( | |
slot: i16; | |
dither: i16; | |
useAMUX: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Peek_DAQ_Event ( | |
timeOut: u32; | |
handle: pi16; | |
msg: pi16; | |
wParam: pi16; | |
lParam: pi32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function REG_Level_Read ( | |
slot: i16; | |
registerIndex: i16; | |
registerValue: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function REG_Level_Write ( | |
slot: i16; | |
registerIndex: i16; | |
bitsAffected: u32; | |
bitSettings: u32; | |
registerValue: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function RTSI_Clear ( | |
slot: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function RTSI_Clock ( | |
slot: i16; | |
connect: i16; | |
direction: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function RTSI_Conn ( | |
slot: i16; | |
brdSignal: i16; | |
busLine: i16; | |
direction: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function RTSI_DisConn ( | |
slot: i16; | |
brdSignal: i16; | |
busLine: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SC_2040_Config ( | |
deviceNumber: i16; | |
channel: i16; | |
sc2040Gain: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCAN_Demux ( | |
buffer: pi16; | |
cnt: u32; | |
numChans: i16; | |
muxMode: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCAN_Op ( | |
slot: i16; | |
numChans: i16; | |
chans: pi16; | |
gains: pi16; | |
buffer: pi16; | |
cnt: u32; | |
sampleRate: f64; | |
scanRate: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCAN_Sequence_Demux ( | |
numChans: i16; | |
chanVector: pi16; | |
bufferSize: u32; | |
buffer: pi16; | |
samplesPerSequence: i16; | |
scanSequenceVector: pi16; | |
samplesPerChanVector: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCAN_Sequence_Retrieve ( | |
deviceNumber: i16; | |
samplesPerSequence: i16; | |
scanSequenceVector: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCAN_Sequence_Setup ( | |
deviceNumber: i16; | |
numChans: i16; | |
chanVector: pi16; | |
gainVector: pi16; | |
scanRateDivVector: pi16; | |
scansPerSequence: pi16; | |
samplesPerSequence: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCAN_Setup ( | |
slot: i16; | |
num_chans: i16; | |
chans: pi16; | |
gains: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCAN_Start ( | |
slot: i16; | |
buffer: pi16; | |
cnt: u32; | |
tb1: i16; | |
si1: u16; | |
tb2: i16; | |
si2: u16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCAN_to_Disk ( | |
slot: i16; | |
numChans: i16; | |
chans: pi16; | |
gains: pi16; | |
fileName: pi8; | |
cnt: u32; | |
sampleRate: f64; | |
scanRate: f64; | |
concat: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Calibrate_1200 ( | |
deviceNumber: i16; | |
calOP: i16; | |
saveNewCal: i16; | |
EEPROMloc: i16; | |
calRefChan: i16; | |
grndRefChan: i16; | |
DAC0chan: i16; | |
DAC1chan: i16; | |
calRefVolts: f64; | |
gain: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_AO_Write ( | |
chassisID: i16; | |
moduleSlot: i16; | |
DACchannel: i16; | |
opCode: i16; | |
rangeCode: i16; | |
voltCurrentData: f64; | |
binaryDat: i16; | |
binaryWritten: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Cal_Constants ( | |
chassisID: i16; | |
moduleSlot: i16; | |
SCXIchannel: i16; | |
operation: i16; | |
calArea: i16; | |
rangeCode: i16; | |
SCXIgain: f64; | |
DAQdevice: i16; | |
DAQchannel: i16; | |
DAQgain: i16; | |
TBgain: f64; | |
volt1: f64; | |
binary1: f64; | |
volt2: f64; | |
binary2: f64; | |
binEEprom1: pf64; | |
binEEprom2: pf64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Calibrate ( | |
chassisID: i16; | |
moduleSlot: i16; | |
moduleChan: i16; | |
operation: i16; | |
calArea: i16; | |
SCXIgain: f64; | |
inputRefVoltage: f64; | |
DAQdevice: i16; | |
DAQchan: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Strain_Null ( | |
chassisID: i16; | |
slot: i16; | |
moduleChan: i16; | |
device: i16; | |
DAQchan: i16; | |
imbalances: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Calibrate_Setup ( | |
chassisID: i16; | |
moduleSlot: i16; | |
calOp: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Change_Chan ( | |
chassisID: i16; | |
moduleSlot: i16; | |
chan: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Set_Excitation ( | |
chassisID: i16; | |
moduleSlot: i16; | |
channel: i16; | |
excitationType: i16; | |
excitation: f32; | |
actualExcitation: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Configure_Connection ( | |
chassisID: i16; | |
moduleSlot: i16; | |
channel: i16; | |
connectionType: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Configure_Filter ( | |
chassisID: i16; | |
moduleSlot: i16; | |
channel: i16; | |
filterMode: i16; | |
freq: f64; | |
cutoffDivDown: u16; | |
outClkDivDown: u16; | |
actFreq: pf64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Get_Chassis_Info ( | |
chassisID: i16; | |
chassisType: pi16; | |
address: pi16; | |
commMode: pi16; | |
commPath: pi16; | |
numSlots: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Get_Module_Info ( | |
chassisID: i16; | |
slot: i16; | |
modulePresent: pi32; | |
opMode: pi16; | |
DAQboard: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Get_State ( | |
chassisID: i16; | |
moduleSlot: i16; | |
port: i16; | |
channel: i16; | |
data: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Get_Status ( | |
chassisID: i16; | |
moduleSlot: i16; | |
wait: i16; | |
data: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Load_Config ( | |
chassisID: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_MuxCtr_Setup ( | |
slot: i16; | |
enable: i16; | |
scanDiv: i16; | |
muxCtrVal: u16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Reset ( | |
chassisID: i16; | |
moduleSlot: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Scale ( | |
chassisID: i16; | |
moduleSlot: i16; | |
SCXIchannel: i16; | |
SCXIgain: f64; | |
TBgain: f64; | |
DAQdevice: i16; | |
DAQchannel: i16; | |
DAQgain: i16; | |
numPoints: u32; | |
binArray: pi16; | |
voltArray: pf64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_SCAN_Setup ( | |
chassisID: i16; | |
numModules: i16; | |
modules: pi16; | |
numChans: pi16; | |
startChans: pi16; | |
DAQboard: i16; | |
modeFlag: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Set_Config ( | |
chassisID: i16; | |
chassisType: i16; | |
address: i16; | |
commMode: i16; | |
slotOrCOMM: i16; | |
numSlots: i16; | |
moduleTypes: pi32; | |
opModes: pi16; | |
DAQboards: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Set_Gain ( | |
chassisID: i16; | |
moduleSlot: i16; | |
channel: i16; | |
gain: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Set_Input_Mode ( | |
chassisID: i16; | |
moduleSlot: i16; | |
inputMode: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Set_State ( | |
chassisID: i16; | |
moduleSlot: i16; | |
port: i16; | |
channel: i16; | |
data: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Single_Chan_Setup ( | |
chassisID: i16; | |
moduleSlot: i16; | |
chan: i16; | |
DAQboard: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Track_Hold_Control ( | |
chassisID: i16; | |
moduleSlot: i16; | |
state: i16; | |
DAQboard: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Track_Hold_Setup ( | |
chassisID: i16; | |
moduleSlot: i16; | |
mode: i16; | |
source: i16; | |
send: i16; | |
holdCnt: i16; | |
DAQboard: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Select_Signal ( | |
deviceNumber: i16; | |
signal: u32; | |
source: u32; | |
sourceSpec: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Set_DAQ_Device_Info ( | |
deviceNumber: i16; | |
infoType: u32; | |
infoVal: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Timeout_Config ( | |
slot: i16; | |
numTicks: i32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_Chan_Control ( | |
slot: i16; | |
channel: i16; | |
operation: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_Check ( | |
slot: i16; | |
channel: i16; | |
progress: pi16; | |
itersDone: pu32; | |
pointsDone: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_ClockRate ( | |
slot: i16; | |
group: i16; | |
whickClock: i16; | |
timebase: i16; | |
updateInterval: u32; | |
mode: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_DB_Config ( | |
slot: i16; | |
numChans: i16; | |
chanVect: pi16; | |
DBMode: i16; | |
oldDataStop: i16; | |
partialTransfer: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_DB_HalfReady ( | |
slot: i16; | |
numChans: i16; | |
chanVect: pi16; | |
halfReady: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_DB_Transfer ( | |
slot: i16; | |
numChans: i16; | |
chanVect: pi16; | |
buffer: pi16; | |
cnt: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_from_Disk ( | |
slot: i16; | |
numChans: i16; | |
chanVect: pi16; | |
fileName: pi8; | |
startPts: u32; | |
endPts: u32; | |
iterations: u32; | |
rate: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_Group_Control ( | |
slot: i16; | |
group: i16; | |
operation: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_Group_Setup ( | |
slot: i16; | |
numChans: i16; | |
chanVect: pi16; | |
group: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_Load ( | |
slot: i16; | |
numChans: i16; | |
chanVect: pi16; | |
buffer: pi16; | |
cnt: u32; | |
iterations: u32; | |
mode: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_Op ( | |
slot: i16; | |
numChans: i16; | |
chanVect: pi16; | |
buffer: pi16; | |
cnt: u32; | |
iterations: u32; | |
rate: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_Rate ( | |
rate: f64; | |
units: i16; | |
timebase: pi16; | |
updateInterval: pu32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_Scale ( | |
slot: i16; | |
chan: i16; | |
cnt: u32; | |
gain: f64; | |
voltArray: pf64; | |
binArray: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_Read_Scan ( | |
slot: i16; | |
reading: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_VRead_Scan ( | |
slot: i16; | |
reading: pf64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_ModuleID_Read ( | |
scxiID: i16; | |
moduleSlot: i16; | |
id: pi32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function USE_E_Series | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_E_Series_AI | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_E_Series_AO | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_E_Series_DIO | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_E_Series_GPCTR | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_E_Series_GPCTR_Simple | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_E_Series_Misc | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_E_Series_WFM | |
:nidaqStatus; stdcall; external nidaqdll; | |
function AO_VScale ( | |
slot: i16; | |
chan: i16; | |
voltage: f64; | |
value: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function GPCTR_Change_Parameter ( | |
deviceNumber: i16; | |
gpCounterNumber: u32; | |
paramID: u32; | |
paramValue: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function USE_E_Series_DAQ | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_MIO | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_LPM | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_LAB | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_DIO_96 | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_DIO_32F | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_DIO_24 | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_AO_610 | |
:nidaqStatus; stdcall; external nidaqdll; | |
function USE_AO_2DC | |
:nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Trigger_Config ( | |
slot: i16; | |
grp: i16; | |
startTrig: i16; | |
startPol: i16; | |
stopTrig: i16; | |
stopPol: i16; | |
ptsAfterStopTrig: u32; | |
pattern: u32; | |
patternMask: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function SCXI_Set_Threshold ( | |
chassisID: i16; | |
moduleSlot: i16; | |
channel: i16; | |
threshHold: f64; | |
hysteresis: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function WFM_Set_Clock ( | |
slot: i16; | |
group: i16; | |
whichClock: u32; | |
desiredRate: f64; | |
units: u32; | |
actualRate: pf64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DAQ_Set_Clock ( | |
slot: i16; | |
whichClock: u32; | |
desiredRate: f64; | |
units: u32; | |
actualRate: pf64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Tio_Select_Signal ( | |
deviceNumber: i16; | |
signal: u32; | |
source: u32; | |
sourceSpec: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Tio_Combine_Signals ( | |
deviceNumber: i16; | |
internalLine: u32; | |
logicalExpression: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_In_Prt ( | |
slot: i16; | |
port: i16; | |
pattern: pi32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Out_Prt ( | |
slot: i16; | |
port: i16; | |
pattern: i32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function AI_Get_Overloaded_Channels ( | |
deviceNumber: i16; | |
numChannels: pi16; | |
channelList: pi16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function Calibrate_TIO ( | |
deviceNumber: i16; | |
operation: u32; | |
setOfCalConst: u32; | |
referenceFreq: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Change_Message_Config ( | |
deviceNumber: i16; | |
operation: i16; | |
riseChanStr: pi8; | |
fallChanStr: pi8; | |
handle: HWND; | |
msg: i16; | |
callBackAddr: u32 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Change_Message_Control ( | |
deviceNumber: i16; | |
ctrlCode: i16 | |
):nidaqStatus; stdcall; external nidaqdll; | |
function DIG_Filter_Config ( | |
deviceNumber: i16; | |
mode: i16; | |
chanStr: pi8; | |
interval: f64 | |
):nidaqStatus; stdcall; external nidaqdll; | |
implementation | |
end. | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(*********************************************************************) | |
(* *) | |
(* This file contains definitions for constants required for some *) | |
(* of the NI-DAQ functions. *) | |
(* *) | |
(* You should use symbols defined here in your programs; do not *) | |
(* use the numerical values. *) | |
(* *) | |
(* See your NI-DAQ Function Reference Manual for details concerning *) | |
(* use of constants defined here. *) | |
(* *) | |
(*********************************************************************) | |
unit NIDAQCNS; | |
interface | |
CONST ND_ABOVE_HIGH_LEVEL = 11020; | |
ND_AC = 11025; | |
ND_ACK_REQ_EXCHANGE_GR1 = 11030; | |
ND_ACK_REQ_EXCHANGE_GR2 = 11035; | |
ND_ACTIVE = 11037; | |
ND_ADC_RESOLUTION = 11040; | |
ND_AI_CALDAC_COUNT = 11050; | |
ND_AI_CHANNEL_COUNT = 11060; | |
ND_AI_COUPLING = 11055; | |
ND_AI_FIFO_INTERRUPTS = 11600; | |
ND_ANALOG_FILTER = 11065; | |
ND_AO48XDC_SET_POWERUP_STATE = 42100; | |
ND_AO_CALDAC_COUNT = 11070; | |
ND_AO_CHANNEL_COUNT = 11080; | |
ND_AO_EXT_REF_CAPABLE = 11090; | |
ND_AO_UNIPOLAR_CAPABLE = 11095; | |
ND_ARM = 11100; | |
ND_ARMED = 11200; | |
ND_ATC_OUT = 11250; | |
ND_ATTENUATION = 11260; | |
ND_AUTOINCREMENT_COUNT = 11300; | |
ND_AUTOMATIC = 11400; | |
ND_AVAILABLE_POINTS = 11500; | |
ND_BASE_ADDRESS = 12100; | |
ND_BELOW_LOW_LEVEL = 12130; | |
ND_BOARD_CLOCK = 12170; | |
ND_BUFFERED_EVENT_CNT = 12200; | |
ND_BUFFERED_PERIOD_MSR = 12300; | |
ND_BUFFERED_PULSE_WIDTH_MSR = 12400; | |
ND_BUFFERED_SEMI_PERIOD_MSR = 12500; | |
ND_BURST = 12600; | |
ND_BURST_INTERVAL = 12700; | |
ND_CAL_CONST_AUTO_LOAD = 13050; | |
ND_CALIBRATION_ENABLE = 13055; | |
ND_CALIBRATION_FRAME_SIZE = 13060; | |
ND_CALIBRATION_FRAME_PTR = 13065; | |
ND_CJ_TEMP = ($8000); | |
ND_CALGND = ($8001); | |
ND_CLEAN_UP = 13100; | |
ND_CLOCK_REVERSE_MODE_GR1 = 13120; | |
ND_CLOCK_REVERSE_MODE_GR2 = 13130; | |
ND_CONFIG_MEMORY_SIZE = 13150; | |
ND_CONTINUOUS = 13160; | |
ND_COUNT = 13200; | |
ND_COUNTER_0 = 13300; | |
ND_COUNTER_1 = 13400; | |
ND_COUNTER_2 = 13310; | |
ND_COUNTER_3 = 13320; | |
ND_COUNTER_4 = 13330; | |
ND_COUNTER_5 = 13340; | |
ND_COUNTER_6 = 13350; | |
ND_COUNTER_7 = 13360; | |
ND_COUNTER_1_SOURCE = 13430; | |
ND_COUNT_AVAILABLE = 13450; | |
ND_COUNT_DOWN = 13465; | |
ND_COUNT_UP = 13485; | |
ND_COUNT_1 = 13500; | |
ND_COUNT_2 = 13600; | |
ND_COUNT_3 = 13700; | |
ND_COUNT_4 = 13800; | |
ND_CURRENT_OUTPUT = 40200; | |
ND_DAC_RESOLUTION = 13950; | |
ND_DATA_TRANSFER_CONDITION = 13960; | |
ND_DATA_XFER_MODE_AI = 14000; | |
ND_DATA_XFER_MODE_AO_GR1 = 14100; | |
ND_DATA_XFER_MODE_AO_GR2 = 14200; | |
ND_DATA_XFER_MODE_DIO_GR1 = 14300; | |
ND_DATA_XFER_MODE_DIO_GR2 = 14400; | |
ND_DATA_XFER_MODE_DIO_GR3 = 14500; | |
ND_DATA_XFER_MODE_DIO_GR4 = 14600; | |
ND_DATA_XFER_MODE_DIO_GR5 = 14700; | |
ND_DATA_XFER_MODE_DIO_GR6 = 14800; | |
ND_DATA_XFER_MODE_DIO_GR7 = 14900; | |
ND_DATA_XFER_MODE_DIO_GR8 = 15000; | |
ND_DATA_XFER_MODE_GPCTR0 = 15100; | |
ND_DATA_XFER_MODE_GPCTR1 = 15200; | |
ND_DATA_XFER_MODE_GPCTR2 = 15110; | |
ND_DATA_XFER_MODE_GPCTR3 = 15120; | |
ND_DATA_XFER_MODE_GPCTR4 = 15130; | |
ND_DATA_XFER_MODE_GPCTR5 = 15140; | |
ND_DATA_XFER_MODE_GPCTR6 = 15150; | |
ND_DATA_XFER_MODE_GPCTR7 = 15160; | |
ND_DATA_XFER_MODE_GPCTR8 = 15165; | |
ND_DATA_XFER_MODE_GPCTR9 = 15170; | |
ND_DATA_XFER_MODE_GPCTR10 = 15175; | |
ND_DATA_XFER_MODE_GPCTR11 = 15180; | |
ND_DC = 15250; | |
ND_DDS_BUFFER_SIZE = 15255; | |
ND_DEVICE_NAME = 15260; | |
ND_DEVICE_POWER = 15270; | |
ND_DEVICE_SERIAL_NUMBER = 15280; | |
ND_DEVICE_STATE_DURING_SUSPEND_MODE = 15290; | |
ND_DEVICE_TYPE_CODE = 15300; | |
ND_DIGITAL_FILTER = 15350; | |
ND_DIGITAL_RESTART = 15375; | |
ND_DIO128_GET_PORT_THRESHOLD = 41200; | |
ND_DIO128_SELECT_INPUT_PORT = 41100; | |
ND_DIO128_SET_PORT_THRESHOLD = 41300; | |
ND_DISABLED = 15400; | |
ND_DISARM = 15450; | |
ND_DIVIDE_DOWN_SAMPLING_SUPPORTED = 15475; | |
ND_DMA_A_LEVEL = 15500; | |
ND_DMA_B_LEVEL = 15600; | |
ND_DMA_C_LEVEL = 15700; | |
ND_DONE = 15800; | |
ND_DONT_CARE = 15900; | |
ND_DONT_KNOW = 15950; | |
ND_EDGE_SENSITIVE = 16000; | |
ND_ENABLED = 16050; | |
ND_END = 16055; | |
ND_EXTERNAL = 16060; | |
ND_EXTERNAL_CALIBRATE = 16100; | |
ND_FACTORY_CALIBRATION_EQUIP = 16210; | |
ND_FACTORY_EEPROM_AREA = 16220; | |
ND_FIFO_EMPTY = 16230; | |
ND_FIFO_HALF_FULL_OR_LESS = 16240; | |
ND_FIFO_HALF_FULL_OR_LESS_UNTIL_FULL = 16245; | |
ND_FIFO_NOT_FULL = 16250; | |
ND_FIFO_TRANSFER_COUNT = 16260; | |
ND_FILTER_CORRECTION_FREQ = 16300; | |
ND_FOREGROUND = 16350; | |
ND_FREQ_OUT = 16400; | |
ND_FSK = 16500; | |
ND_EDGE_BASED_FSK = 16500; | |
ND_GATE = 17100; | |
ND_GATE_POLARITY = 17200; | |
ND_GPCTR0_GATE = 17300; | |
ND_GPCTR0_OUTPUT = 17400; | |
ND_GPCTR0_SOURCE = 17500; | |
ND_GPCTR1_GATE = 17600; | |
ND_GPCTR1_OUTPUT = 17700; | |
ND_GPCTR1_SOURCE = 17800; | |
ND_GPCTR2_GATE = 17320; | |
ND_GPCTR2_OUTPUT = 17420; | |
ND_GPCTR2_SOURCE = 17520; | |
ND_GPCTR3_GATE = 17330; | |
ND_GPCTR3_OUTPUT = 17430; | |
ND_GPCTR3_SOURCE = 17530; | |
ND_GPCTR4_GATE = 17340; | |
ND_GPCTR4_OUTPUT = 17440; | |
ND_GPCTR4_SOURCE = 17540; | |
ND_GPCTR5_GATE = 17350; | |
ND_GPCTR5_OUTPUT = 17450; | |
ND_GPCTR5_SOURCE = 17550; | |
ND_GPCTR6_GATE = 17360; | |
ND_GPCTR6_OUTPUT = 17460; | |
ND_GPCTR6_SOURCE = 17660; | |
ND_GPCTR7_GATE = 17370; | |
ND_GPCTR7_OUTPUT = 17470; | |
ND_GPCTR7_SOURCE = 17570; | |
ND_GROUND_DAC_REFERENCE = 17900; | |
ND_HARDWARE = 18000; | |
ND_HI_RES_SAMPLING = 18020; | |
ND_HIGH = 18050; | |
ND_HIGH_HYSTERESIS = 18080; | |
ND_HIGH_TO_LOW = 18100; | |
ND_HW_ANALOG_TRIGGER = 18900; | |
ND_IMPEDANCE = 19000; | |
ND_INACTIVE = 19010; | |
ND_INITIAL_COUNT = 19100; | |
ND_INIT_PLUGPLAY_DEVICES = 19110; | |
ND_INSIDE_REGION = 19150; | |
ND_INTERNAL = 19160; | |
ND_INTERNAL_100_KHZ = 19200; | |
ND_INTERNAL_10_MHZ = 19300; | |
ND_INTERNAL_1250_KHZ = 19320; | |
ND_INTERNAL_20_MHZ = 19400; | |
ND_INTERNAL_25_MHZ = 19410; | |
ND_INTERNAL_2500_KHZ = 19420; | |
ND_INTERNAL_5_MHZ = 19450; | |
ND_INTERNAL_7160_KHZ = 19460; | |
ND_INTERNAL_TIMER = 19500; | |
ND_INTERRUPTS = 19600; | |
ND_INTERRUPT_A_LEVEL = 19700; | |
ND_INTERRUPT_B_LEVEL = 19800; | |
ND_INTERRUPT_TRIGGER_MODE = 19850; | |
ND_IN_CHANNEL_CLOCK_TIMEBASE = 19900; | |
ND_IN_CHANNEL_CLOCK_TB_POL = 20000; | |
ND_IN_CONVERT = 20100; | |
ND_IN_CONVERT_POL = 20200; | |
ND_IN_DATA_FIFO_SIZE = 20250; | |
ND_IN_EXTERNAL_GATE = 20300; | |
ND_IN_EXTERNAL_GATE_POL = 20400; | |
ND_IN_SCAN_CLOCK_TIMEBASE = 20500; | |
ND_IN_SCAN_CLOCK_TB_POL = 20600; | |
ND_IN_SCAN_IN_PROG = 20650; | |
ND_IN_SCAN_START = 20700; | |
ND_IN_SCAN_START_POL = 20800; | |
ND_IN_START_TRIGGER = 20900; | |
ND_IN_START_TRIGGER_POL = 21000; | |
ND_IN_STOP_TRIGGER = 21100; | |
ND_IN_STOP_TRIGGER_POL = 21200; | |
ND_INT_AI_GND = 21210; | |
ND_INT_AO_CH_0 = 21230; | |
ND_INT_AO_CH_0_VS_REF_5V = 21235; | |
ND_INT_AO_CH_1 = 21240; | |
ND_INT_AO_CH_1_VS_AO_CH_0 = 21245; | |
ND_INT_AO_CH_1_VS_REF_5V = 21250; | |
ND_INT_AO_CH_2 = 21220; | |
ND_INT_AO_CH_3 = 21221; | |
ND_INT_AO_CH_4 = 21222; | |
ND_INT_AO_CH_5 = 21223; | |
ND_INT_AO_CH_6 = 21224; | |
ND_INT_AO_CH_7 = 21225; | |
ND_INT_AO_GND = 21260; | |
ND_INT_AO_GND_VS_AI_GND = 21265; | |
ND_INT_CM_REF_5V = 21270; | |
ND_INT_DEV_TEMP = 21280; | |
ND_INT_REF_5V = 21290; | |
ND_INT_REF_EXTERN = 21296; | |
ND_INT_CAL_BUS = 21295; | |
ND_INT_MUX_BUS = 21305; | |
ND_INT_AI_GND_AMP_0 = 21211; | |
ND_INT_AI_GND_AMP_1 = 21212; | |
ND_INT_AI_GND_AMP_2 = 21213; | |
ND_INT_AI_GND_AMP_3 = 21214; | |
ND_INT_AO_CH_0_AMP_0 = 21231; | |
ND_INT_AO_CH_0_AMP_1 = 21232; | |
ND_INT_AO_CH_0_AMP_2 = 21233; | |
ND_INT_AO_CH_0_AMP_3 = 21234; | |
ND_INT_AO_CH_1_AMP_0 = 21241; | |
ND_INT_AO_CH_1_AMP_1 = 21242; | |
ND_INT_AO_CH_1_AMP_2 = 21243; | |
ND_INT_AO_CH_1_AMP_3 = 21244; | |
ND_INT_AO_CH_0_VS_REF_AMP_0 = 21236; | |
ND_INT_AO_CH_0_VS_REF_AMP_1 = 21237; | |
ND_INT_AO_CH_0_VS_REF_AMP_2 = 21238; | |
ND_INT_AO_CH_0_VS_REF_AMP_3 = 21239; | |
ND_INT_AO_CH_1_VS_REF_AMP_0 = 21251; | |
ND_INT_AO_CH_1_VS_REF_AMP_1 = 21252; | |
ND_INT_AO_CH_1_VS_REF_AMP_2 = 21253; | |
ND_INT_AO_CH_1_VS_REF_AMP_3 = 21254; | |
ND_INT_AO_GND_VS_AI_GND_AMP_0 = 21266; | |
ND_INT_AO_GND_VS_AI_GND_AMP_1 = 21267; | |
ND_INT_AO_GND_VS_AI_GND_AMP_2 = 21268; | |
ND_INT_AO_GND_VS_AI_GND_AMP_3 = 21269; | |
ND_INT_CM_REF_AMP_0 = 21271; | |
ND_INT_CM_REF_AMP_1 = 21272; | |
ND_INT_CM_REF_AMP_2 = 21273; | |
ND_INT_CM_REF_AMP_3 = 21274; | |
ND_INT_REF_AMP_0 = 21291; | |
ND_INT_REF_AMP_1 = 21292; | |
ND_INT_REF_AMP_2 = 21293; | |
ND_INT_REF_AMP_3 = 21294; | |
ND_INTERRUPT_EVERY_SAMPLE = 11700; | |
ND_INTERRUPT_HALF_FIFO = 11800; | |
ND_IO_CONNECTOR = 21300; | |
ND_LEVEL_SENSITIVE = 24000; | |
ND_LINK_COMPLETE_INTERRUPTS = 24010; | |
ND_LOW = 24050; | |
ND_LOW_HYSTERESIS = 24080; | |
ND_LOW_TO_HIGH = 24100; | |
ND_LPT_DEVICE_MODE = 24200; | |
ND_MARKER = 24500; | |
ND_MARKER_QUANTUM = 24550; | |
ND_MAX_ARB_SEQUENCE_LENGTH = 24600; | |
ND_MAX_FUNC_SEQUENCE_LENGTH = 24610; | |
ND_MAX_LOOP_COUNT = 24620; | |
ND_MAX_NUM_WAVEFORMS = 24630; | |
ND_MAX_SAMPLE_RATE = 24640; | |
ND_MAX_WFM_SIZE = 24650; | |
ND_MEMORY_TRANSFER_WIDTH = 24700; | |
ND_MIN_SAMPLE_RATE = 24800; | |
ND_MIN_WFM_SIZE = 24810; | |
ND_NEGATIVE = 26100; | |
ND_NEW = 26190; | |
ND_NI_DAQ_SW_AREA = 26195; | |
ND_NO = 26200; | |
ND_NO_STRAIN_GAUGE = 26225; | |
ND_NO_TRACK_AND_HOLD = 26250; | |
ND_NONE = 26300; | |
ND_NOT_APPLICABLE = 26400; | |
ND_NUMBER_DIG_PORTS = 26500; | |
ND_OFF = 27010; | |
ND_OFFSET = 27020; | |
ND_ON = 27050; | |
ND_OTHER = 27060; | |
ND_OTHER_GPCTR_OUTPUT = 27300; | |
ND_OTHER_GPCTR_TC = 27400; | |
ND_OUT_DATA_FIFO_SIZE = 27070; | |
ND_OUT_EXTERNAL_GATE = 27080; | |
ND_OUT_EXTERNAL_GATE_POL = 27082; | |
ND_OUT_START_TRIGGER = 27100; | |
ND_OUT_START_TRIGGER_POL = 27102; | |
ND_OUT_UPDATE = 27200; | |
ND_OUT_UPDATE_POL = 27202; | |
ND_OUT_UPDATE_CLOCK_TIMEBASE = 27210; | |
ND_OUT_UPDATE_CLOCK_TB_POL = 27212; | |
ND_OUTPUT_ENABLE = 27220; | |
ND_OUTPUT_MODE = 27230; | |
ND_OUTPUT_POLARITY = 27240; | |
ND_OUTPUT_STATE = 27250; | |
ND_OUTPUT_TYPE = 40000; | |
ND_DIGITAL_PATTERN_GENERATION = 28030; | |
ND_PAUSE = 28040; | |
ND_PAUSE_ON_HIGH = 28045; | |
ND_PAUSE_ON_LOW = 28050; | |
ND_PFI_0 = 28100; | |
ND_PFI_1 = 28200; | |
ND_PFI_2 = 28300; | |
ND_PFI_3 = 28400; | |
ND_PFI_4 = 28500; | |
ND_PFI_5 = 28600; | |
ND_PFI_6 = 28700; | |
ND_PFI_7 = 28800; | |
ND_PFI_8 = 28900; | |
ND_PFI_9 = 29000; | |
ND_PFI_10 = 50280; | |
ND_PFI_11 = 50290; | |
ND_PFI_12 = 50300; | |
ND_PFI_13 = 50310; | |
ND_PFI_14 = 50320; | |
ND_PFI_15 = 50330; | |
ND_PFI_16 = 50340; | |
ND_PFI_17 = 50350; | |
ND_PFI_18 = 50360; | |
ND_PFI_19 = 50370; | |
ND_PFI_20 = 50380; | |
ND_PFI_21 = 50390; | |
ND_PFI_22 = 50400; | |
ND_PFI_23 = 50410; | |
ND_PFI_24 = 50420; | |
ND_PFI_25 = 50430; | |
ND_PFI_26 = 50440; | |
ND_PFI_27 = 50450; | |
ND_PFI_28 = 50460; | |
ND_PFI_29 = 50470; | |
ND_PFI_30 = 50480; | |
ND_PFI_31 = 50490; | |
ND_PFI_32 = 50500; | |
ND_PFI_33 = 50510; | |
ND_PFI_34 = 50520; | |
ND_PFI_35 = 50530; | |
ND_PFI_36 = 50540; | |
ND_PFI_37 = 50550; | |
ND_PFI_38 = 50560; | |
ND_PFI_39 = 50570; | |
ND_PLL_REF_FREQ = 29010; | |
ND_PLL_REF_SOURCE = 29020; | |
ND_PRE_ARM = 29050; | |
ND_POSITIVE = 29100; | |
ND_PREPARE = 29200; | |
ND_PROGRAM = 29300; | |
ND_PULSE = 29350; | |
ND_PULSE_SOURCE = 29500; | |
ND_PULSE_TRAIN_GNR = 29600; | |
ND_PXI_BACKPLANE_CLOCK = 29900; | |
ND_REGLITCH = 31000; | |
ND_RESERVED = 31100; | |
ND_RESET = 31200; | |
ND_RESUME = 31250; | |
ND_RETRIG_PULSE_GNR = 31300; | |
ND_REVISION = 31350; | |
ND_RTSI_0 = 31400; | |
ND_RTSI_1 = 31500; | |
ND_RTSI_2 = 31600; | |
ND_RTSI_3 = 31700; | |
ND_RTSI_4 = 31800; | |
ND_RTSI_5 = 31900; | |
ND_RTSI_6 = 32000; | |
ND_RTSI_CLOCK = 32100; | |
ND_SCANCLK = 32400; | |
ND_SCANCLK_LINE = 32420; | |
ND_SC_2040_MODE = 32500; | |
ND_SC_2043_MODE = 32600; | |
ND_SELF_CALIBRATE = 32700; | |
ND_SET_DEFAULT_LOAD_AREA = 32800; | |
ND_RESTORE_FACTORY_CALIBRATION = 32810; | |
ND_SET_POWERUP_STATE = 42100; | |
ND_SIMPLE_EVENT_CNT = 33100; | |
ND_SINGLE = 33150; | |
ND_SINGLE_PERIOD_MSR = 33200; | |
ND_SINGLE_PULSE_GNR = 33300; | |
ND_SINGLE_PULSE_WIDTH_MSR = 33400; | |
ND_SINGLE_TRIG_PULSE_GNR = 33500; | |
ND_SOURCE = 33700; | |
ND_SOURCE_POLARITY = 33800; | |
ND_STABLE_10_MHZ = 33810; | |
ND_STEPPED = 33825; | |
ND_STRAIN_GAUGE = 33850; | |
ND_STRAIN_GAUGE_EX0 = 33875; | |
ND_SUB_REVISION = 33900; | |
ND_SYNC_DUTY_CYCLE_HIGH = 33930; | |
ND_SYNC_OUT = 33970; | |
ND_TC_REACHED = 34100; | |
ND_THE_AI_CHANNEL = 34400; | |
ND_TOGGLE = 34700; | |
ND_TOGGLE_GATE = 34800; | |
ND_TRACK_AND_HOLD = 34850; | |
ND_TRIG_PULSE_WIDTH_MSR = 34900; | |
ND_TRIGGER_SOURCE = 34930; | |
ND_TRIGGER_MODE = 34970; | |
ND_UI2_TC = 35100; | |
ND_UP_DOWN = 35150; | |
ND_UP_TO_1_DMA_CHANNEL = 35200; | |
ND_UP_TO_2_DMA_CHANNELS = 35300; | |
ND_USE_CAL_CHAN = 36000; | |
ND_USE_AUX_CHAN = 36100; | |
ND_USER_EEPROM_AREA = 37000; | |
ND_USER_EEPROM_AREA_2 = 37010; | |
ND_USER_EEPROM_AREA_3 = 37020; | |
ND_USER_EEPROM_AREA_4 = 37030; | |
ND_USER_EEPROM_AREA_5 = 37040; | |
ND_DSA_RTSI_CLOCK_AD = 44000; | |
ND_DSA_RTSI_CLOCK_DA = 44010; | |
ND_DSA_OUTPUT_TRIGGER = 44020; | |
ND_DSA_INPUT_TRIGGER = 44030; | |
ND_DSA_SHARC_TRIGGER = 44040; | |
ND_DSA_ANALOG_TRIGGER = 44050; | |
ND_DSA_HOST_TRIGGER = 44060; | |
ND_DSA_EXTERNAL_DIGITAL_TRIGGER = 44070; | |
ND_VOLTAGE_OUTPUT = 40100; | |
ND_VOLTAGE_REFERENCE = 38000; | |
ND_VXI_SC = ($2000); | |
ND_PXI_SC = ($2010); | |
ND_VXIMIO_SET_ALLOCATE_MODE = 43100; | |
ND_VXIMIO_USE_ONBOARD_MEMORY_AI = 43500; | |
ND_VXIMIO_USE_ONBOARD_MEMORY_AO = 43600; | |
ND_VXIMIO_USE_ONBOARD_MEMORY_GPCTR = 43700; | |
ND_VXIMIO_USE_PC_MEMORY_AI = 43200; | |
ND_VXIMIO_USE_PC_MEMORY_AO = 43300; | |
ND_VXIMIO_USE_PC_MEMORY_GPCTR = 43400; | |
ND_WFM_QUANTUM = 45000; | |
ND_YES = 39100; | |
ND_3V_LEVEL = 43450; | |
ND_WRITE_MARK = 50000; | |
ND_READ_MARK = 50010; | |
ND_BUFFER_START = 50020; | |
ND_TRIGGER_POINT = 50025; | |
ND_BUFFER_MODE = 50030; | |
ND_DOUBLE = 50050; | |
ND_QUADRATURE_ENCODER_X1 = 50070; | |
ND_QUADRATURE_ENCODER_X2 = 50080; | |
ND_QUADRATURE_ENCODER_X4 = 50090; | |
ND_TWO_PULSE_COUNTING = 50100; | |
ND_LINE_FILTER = 50110; | |
ND_SYNCHRONIZATION = 50120; | |
ND_5_MICROSECONDS = 50130; | |
ND_1_MICROSECOND = 50140; | |
ND_500_NANOSECONDS = 50150; | |
ND_100_NANOSECONDS = 50160; | |
ND_1_MILLISECOND = 50170; | |
ND_10_MILLISECONDS = 50180; | |
ND_100_MILLISECONDS = 50190; | |
ND_OTHER_GPCTR_SOURCE = 50580; | |
ND_OTHER_GPCTR_GATE = 50590; | |
ND_AUX_LINE = 50600; | |
ND_AUX_LINE_POLARITY = 50610; | |
ND_TWO_SIGNAL_EDGE_SEPARATION_MSR = 50630; | |
ND_BUFFERED_TWO_SIGNAL_EDGE_SEPARATION_MSR = 50640; | |
ND_SWITCH_CYCLE = 50650; | |
ND_INTERNAL_MAX_TIMEBASE = 50660; | |
ND_PRESCALE_VALUE = 50670; | |
ND_MAX_PRESCALE = 50690; | |
ND_INTERNAL_LINE_0 = 50710; | |
ND_INTERNAL_LINE_1 = 50720; | |
ND_INTERNAL_LINE_2 = 50730; | |
ND_INTERNAL_LINE_3 = 50740; | |
ND_INTERNAL_LINE_4 = 50750; | |
ND_INTERNAL_LINE_5 = 50760; | |
ND_INTERNAL_LINE_6 = 50770; | |
ND_INTERNAL_LINE_7 = 50780; | |
ND_INTERNAL_LINE_8 = 50790; | |
ND_INTERNAL_LINE_9 = 50800; | |
ND_INTERNAL_LINE_10 = 50810; | |
ND_INTERNAL_LINE_11 = 50820; | |
ND_INTERNAL_LINE_12 = 50830; | |
ND_INTERNAL_LINE_13 = 50840; | |
ND_INTERNAL_LINE_14 = 50850; | |
ND_INTERNAL_LINE_15 = 50860; | |
ND_INTERNAL_LINE_16 = 50862; | |
ND_INTERNAL_LINE_17 = 50864; | |
ND_INTERNAL_LINE_18 = 50866; | |
ND_INTERNAL_LINE_19 = 50868; | |
ND_INTERNAL_LINE_20 = 50870; | |
ND_INTERNAL_LINE_21 = 50872; | |
ND_INTERNAL_LINE_22 = 50874; | |
ND_INTERNAL_LINE_23 = 50876; | |
ND_START_TRIGGER = 51150; | |
ND_START_TRIGGER_POLARITY = 51151; | |
ND_COUNTING_SYNCHRONOUS = 51200; | |
ND_SYNCHRONOUS = 51210; | |
ND_ASYNCHRONOUS = 51220; | |
ND_CONFIGURABLE_FILTER = 51230; | |
ND_ENCODER_TYPE = 51240; | |
ND_Z_INDEX_ACTIVE = 51250; | |
ND_Z_INDEX_VALUE = 51260; | |
ND_SNAPSHOT = 51270; | |
ND_POSITION_MSR = 51280; | |
ND_BUFFERED_POSITION_MSR = 51290; | |
ND_SAVED_COUNT = 51300; | |
ND_READ_MARK_H_SNAPSHOT = 51310; | |
ND_READ_MARK_L_SNAPSHOT = 51320; | |
ND_WRITE_MARK_H_SNAPSHOT = 51330; | |
ND_WRITE_MARK_L_SNAPSHOT = 51340; | |
ND_BACKLOG_H_SNAPSHOT = 51350; | |
ND_BACKLOG_L_SNAPSHOT = 51360; | |
ND_ARMED_SNAPSHOT = 51370; | |
ND_EDGE_GATED_FSK = 51371; | |
ND_SIMPLE_GATED_EVENT_CNT = 51372; | |
ND_VIDEO_TYPE = 51380; | |
ND_PAL_B = 51390; | |
ND_PAL_G = 51400; | |
ND_PAL_H = 51410; | |
ND_PAL_I = 51420; | |
ND_PAL_D = 51430; | |
ND_PAL_N = 51440; | |
ND_PAL_M = 51450; | |
ND_NTSC_M = 51460; | |
ND_COUNTER_TYPE = 51470; | |
ND_NI_TIO = 51480; | |
ND_AM9513 = 51490; | |
ND_STC = 51500; | |
ND_8253 = 51510; | |
ND_A_HIGH_B_HIGH = 51520; | |
ND_A_HIGH_B_LOW = 51530; | |
ND_A_LOW_B_HIGH = 51540; | |
ND_A_LOW_B_LOW = 51550; | |
ND_Z_INDEX_RELOAD_PHASE = 51560; | |
ND_UPDOWN_LINE = 51570; | |
ND_DEFAULT_PFI_LINE = 51580; | |
ND_BUFFER_SIZE = 51590; | |
ND_ELEMENT_SIZE = 51600; | |
ND_NUMBER_GP_COUNTERS = 51610; | |
ND_BUFFERED_TIME_STAMPING = 51620; | |
ND_TIME_0_DATA_32 = 51630; | |
ND_TIME_8_DATA_24 = 51640; | |
ND_TIME_16_DATA_16 = 51650; | |
ND_TIME_24_DATA_8 = 51660; | |
ND_TIME_32_DATA_32 = 51670; | |
ND_TIME_48_DATA_16 = 51680; | |
ND_ABSOLUTE = 51690; | |
ND_RELATIVE = 51700; | |
ND_TIME_DATA_SIZE = 51710; | |
ND_TIME_FORMAT = 51720; | |
ND_HALT_ON_OVERFLOW = 51730; | |
ND_OVERLAY_RTSI_ON_PFI_LINES = 51740; | |
ND_STOP_TRIGGER = 51750; | |
ND_TS_INPUT_MODE = 51760; | |
ND_BOTH_EDGES = 51770; | |
ND_CLOCK_0 = 51780; | |
ND_CLOCK_1 = 51790; | |
ND_CLOCK_2 = 51800; | |
ND_CLOCK_3 = 51810; | |
ND_SYNCHRONIZATION_LINE = 51820; | |
ND_TRANSFER_METHOD = 51830; | |
ND_SECONDS = 51840; | |
ND_PRECISION = 51850; | |
ND_NANO_SECONDS = 51860; | |
ND_SYNCHRONIZATION_METHOD = 51870; | |
ND_PULSE_PER_SECOND = 51880; | |
ND_IRIG_B = 51890; | |
ND_SIMPLE_TIME_MSR = 51900; | |
ND_SINGLE_TIME_MSR = 51910; | |
ND_BUFFERED_TIME_MSR = 51920; | |
ND_DMA = 51930; | |
implementation | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit DetectROIDlgu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
StdCtrls, Spin, Buttons, ExtCtrls, Mpfileu; | |
type | |
TDetectROIDlg = class(TForm) | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
GroupBox1: TGroupBox; | |
Label1: TLabel; | |
SpinEdit1: TSpinEdit; | |
Label3: TLabel; | |
SpinEdit2: TSpinEdit; | |
CheckBox1: TCheckBox; | |
GroupBox2: TGroupBox; | |
RadioButton1: TRadioButton; | |
RadioButton3: TRadioButton; | |
RadioButton2: TRadioButton; | |
RadioButton4: TRadioButton; | |
GroupBox3: TGroupBox; | |
Label5: TLabel; | |
Label6: TLabel; | |
SpinEdit5: TSpinEdit; | |
SpinEdit6: TSpinEdit; | |
Label2: TLabel; | |
SpinEdit3: TSpinEdit; | |
Label4: TLabel; | |
SpinEdit4: TSpinEdit; | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
function SelectedCh: integer; | |
procedure SetGUI(aMPFile: TMPFile); | |
end; | |
var | |
DetectROIDlg: TDetectROIDlg; | |
implementation | |
{$R *.DFM} | |
function TDetectROIDlg.SelectedCh: integer; | |
begin | |
if RadioButton1.Checked then | |
Result := 0 | |
else if RadioButton2.Checked then | |
Result :=1 | |
else if RadioButton3.Checked then | |
Result := 2 | |
else if RadioButton4.Checked then | |
Result := 3 | |
else | |
Result := 0; | |
end; | |
procedure TDetectROIDlg.SetGUI(aMPFile: TMPFile); | |
begin | |
with aMPFile do | |
begin | |
RadioButton1.Checked := (DefaultVideoChannel = 0); | |
RadioButton2.Checked := (DefaultVideoChannel = 1); | |
RadioButton3.Checked := (DefaultVideoChannel = 2); | |
RadioButton4.Checked := (DefaultVideoChannel = 3); | |
if VideoChCount = 1 then | |
begin | |
RadioButton1.Enabled := False; | |
RadioButton2.Enabled := False; | |
RadioButton3.Enabled := False; | |
RadioButton4.Enabled := False; | |
end | |
else | |
begin | |
RadioButton1.Enabled := VideoChEnabled[0]; | |
RadioButton2.Enabled := VideoChEnabled[1]; | |
RadioButton3.Enabled := VideoChEnabled[2]; | |
RadioButton4.Enabled := VideoChEnabled[3]; | |
end; | |
end; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit ROIu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
Menus, Trackcur, Horzbaru, ComCtrls, MPUnit, ROIThreadu, ExtCtrls; | |
type | |
TROIFrm = class(TForm) | |
MainMenu1: TMainMenu; | |
Axis1: TMenuItem; | |
XAxis1: TMenuItem; | |
YAxis1: TMenuItem; | |
Data1: TMenuItem; | |
Copydatatoclipboard1: TMenuItem; | |
StatusBar1: TStatusBar; | |
HorzTrackBar1: THorzTrackBar; | |
VertTrackBar1: TVertTrackBar; | |
N1: TMenuItem; | |
ResetCursorRelativeOrigins1: TMenuItem; | |
PopupMenu1: TPopupMenu; | |
ResetRelative1: TMenuItem; | |
N2: TMenuItem; | |
XAxisFullRange1: TMenuItem; | |
YAxisFullRange1: TMenuItem; | |
PreviousMagnification1: TMenuItem; | |
YAxisAutoscale1: TMenuItem; | |
procedure FormResize(Sender: TObject); | |
procedure FormCreate(Sender: TObject); | |
procedure FormDestroy(Sender: TObject); | |
procedure XAxis1Click(Sender: TObject); | |
procedure YAxis1Click(Sender: TObject); | |
procedure FormPaint(Sender: TObject); | |
procedure ResetCursorRelativeOrigins1Click(Sender: TObject); | |
procedure HorzTrackBar1Change(Sender: TObject); | |
procedure Copydatatoclipboard1Click(Sender: TObject); | |
procedure XAxisFullRange1Click(Sender: TObject); | |
procedure SetXAxissize1Click(Sender: TObject); | |
procedure YAxisFullRange1Click(Sender: TObject); | |
procedure YAxisAutoscale1Click(Sender: TObject); | |
procedure PreviousMagnification1Click(Sender: TObject); | |
procedure VertTrackBar1Change(Sender: TObject); | |
private | |
{ Private declarations } | |
bInitialized, {prevents FormPaint before first FormResize} | |
bAdjustingCursorPos: boolean; {prevent activation of OnChange events} | |
fDataSize: integer; | |
fDisplayMode: TDisplayMode; | |
prev_xRight, prev_xWidth, | |
prev_yTop, prev_yHeight: integer; | |
{rectangle areas} | |
bitmapWidth, bitmapHeight: integer; | |
viewRect, | |
xAxisRect, | |
yAxisRect, | |
cornerRect: TRect; | |
xCursorPos, | |
yCursorPos, | |
refXCursorPos, | |
refYCursorPos: integer; | |
roiThread: TROIThread; | |
procedure AdjustCursorPos; | |
procedure AdjustLogicalCursorPos; | |
procedure DrawBitmap; | |
procedure DrawData; | |
procedure DrawXAxis; | |
procedure DrawXCursorOnBitmap; | |
procedure DrawXCursorOnScreen; | |
procedure DrawYAxis; | |
procedure DrawYCursorOnBitmap; | |
procedure DrawYCursorOnScreen; | |
procedure OnMagnificationChanged; | |
function RectBitmapToWindow(aRect: TRect): TRect; | |
function RectWindowToBitmap(aRect: TRect): TRect; | |
procedure ResizeElements; | |
procedure SetDataSize(newSize: integer); | |
procedure SetPrecision(newPrecision: TPrecision); | |
procedure UpdateCursorCaptions; | |
function XBitmapToData(xBitmap: integer): integer; | |
function XDataToBitmap(xData: integer): integer; | |
function YBitmapToData(yBitmap: integer): integer; | |
function YDataToBitmap(yData: integer): integer; | |
public | |
{ Public declarations } | |
f_MAX_Y_VALUE: integer; | |
{axis} | |
xRight, xWidth, | |
yTop, yHeight: integer; {logical values} | |
cXTickMarks, cYTickMarks: integer; | |
channel: integer; | |
ROIRect: TRect; {contains the absolute coordinates of the ROI rectangle} | |
ROIRegion: TRect; {the ROI in the frame buffer} | |
screenBitmapROIRect: TRect; | |
trace: TTrace; | |
ROIThreadMutex: THandle; | |
framesDisplayed: integer; | |
nextFrame: integer; {the index in dataBuffer for the next frame} | |
circdataBuffer: array of integer; {a circular buffer updated by the thread} | |
databuffer: array of integer; {used by TROIFrm to store data: non circular} | |
offscreenBitmap: TBitmap; | |
procedure CopyCircData; {copies circdataBuffer into dataBuffer - used by ROIThread} | |
procedure CopyOffscreenToScreen; {forces update of the screen} | |
procedure OnScanningStart; {resets the circular buffer} | |
procedure OnScanningEnd; | |
procedure RedrawOffscreen; {called by the thread} | |
procedure SavePrevMag; | |
property dataSize: integer read fDataSize write SetDataSize; | |
property displayMode: TDisplayMode write fDisplayMode; | |
property precision: TPrecision write SetPrecision; | |
end; | |
var | |
ROIFrm: TROIFrm; | |
implementation | |
{$R *.DFM} | |
uses ROIAxisDlgu, Mainfrm, Clipbrd; | |
const | |
TRACK_BAR_WIDTH = 17; | |
TRACK_BAR_HEIGHT = 17; | |
Y_AXIS_WIDTH = 75; | |
X_AXIS_HEIGHT = 35; | |
{**************************** PRIVATE METHODS *********************************} | |
procedure TROIFrm.AdjustCursorPos; | |
begin | |
bAdjustingCursorPos := True; | |
VertTrackBar1.Position := Muldiv(yCursorPos - (yTop - yHeight + 1), | |
bitmapHeight - 1, yHeight - 1); | |
HorzTrackBar1.Position := Muldiv(xCursorPos - (xRight + xWidth - 1), bitmapWidth - 1, - xWidth + 1); | |
bAdjustingCursorPos := False; | |
end; | |
procedure TROIFrm.AdjustLogicalCursorPos; | |
begin | |
xCursorPos := XBitmapToData(HorzTrackBar1.Position); | |
yCursorPos := YBitmapToData(VertTrackBar1.Position); | |
end; | |
procedure TROIFrm.DrawBitmap; | |
begin | |
with offscreenBitmap.Canvas do | |
begin | |
Brush.Color := clBlack; | |
FillRect(Rect(0, 0, bitmapWidth - 1, bitmapHeight - 1)); | |
end; | |
end; | |
procedure TROIFrm.DrawData; | |
var lastIndex, firstIndex, i, j, k, indexofnextpt, | |
bufferlimit, dataVal, maxVal, minVal: integer; | |
bitmapY, bitmaprY: integer; | |
firstPPt: ^TPoint; | |
begin | |
if framesDisplayed > 0 then | |
begin | |
lastIndex := -1; firstIndex := -1; | |
if framesDisplayed < dataSize then | |
bufferlimit := nextFrame | |
else | |
bufferlimit := dataSize; | |
for i := bitmapWidth - 1 downto 0 do {index in trace} | |
begin | |
j := XBitmapToData(i); {index in data buffer} | |
indexofnextpt := XBitmapToData(i - 1) - 1; | |
if (j >= 0) and (j < bufferlimit) then | |
begin | |
if lastIndex = -1 then lastIndex := i; | |
firstIndex := i; | |
trace[i].MaxPt.y := dataBuffer[j]; | |
trace[i].MinPt.y := trace[i].MaxPt.y; | |
if (indexofnextPt > j) and (indexofnextPt < bufferlimit) and | |
(j < bufferlimit - 1) then | |
for k := j + 1 to indexofnextPt do | |
begin | |
dataVal := dataBuffer[k]; | |
if dataVal > trace[i].MaxPt.y then trace[i].MaxPt.y := dataVal; | |
if dataVal < trace[i].MinPt.y then trace[i].MinPt.y := dataVal; | |
end; | |
end; {j} | |
end; {i} | |
if (lastIndex <> -1) and (firstIndex <> -1) and (firstIndex < lastIndex) then | |
begin | |
if YAxisAutoscale1.Checked then | |
begin | |
{Autoscale} | |
maxVal := trace[firstIndex].MaxPt.y; | |
minVal := trace[firstIndex].MinPt.y; | |
{find the maximum and minimum values} | |
for i := firstIndex + 1 to lastIndex do | |
begin | |
if maxVal < trace[i].MaxPt.y then maxVal := trace[i].MaxPt.y; | |
if minVal < trace[i].MinPt.y then minVal := trace[i].MinPt.y; | |
end; | |
{at least 100 pixel difference for autoscale} | |
if maxVal >= minVal + 100 then | |
begin | |
bitmapY := YDataToBitmap(YCursorPos); | |
bitmaprY := YDataToBitmap(refYCursorPos); | |
yTop := (maxVal + minVal) div 2 + Muldiv(10, (maxVal - minVal + 1) div 2, 9); | |
yHeight := Muldiv(10, maxVal - minVal + 1, 9); | |
if yTop > f_MAX_Y_VALUE then yTop := f_MAX_Y_VALUE; | |
if yTop - yHeight < - f_MAX_Y_VALUE - 1 then | |
yHeight := f_MAX_Y_VALUE + 1 + yTop; | |
DrawYAxis; | |
YCursorPos := YBitmapToData(bitmapY); | |
refYCursorPos := YBitmapToData(bitmaprY); | |
UpdateCursorCaptions; | |
end; | |
end; | |
{logical to bitmap Y} | |
for i := firstIndex to lastIndex do | |
begin | |
dataVal := trace[i].MaxPt.y; trace[i].MaxPt.y := YDataToBitmap(dataVal); | |
dataVal := trace[i].MinPt.y; trace[i].MinPt.y := YDataToBitmap(dataVal); | |
end; | |
with offscreenbitmap.Canvas do | |
begin | |
Pen.Color := clWhite; | |
Pen.Mode := pmCopy; | |
Pen.Style := psSolid; | |
Pen.Width := 1; | |
end; | |
firstPPt := @trace[firstIndex].MaxPt; | |
Windows.Polyline(offscreenBitmap.Canvas.Handle, firstPPt, | |
2 * (lastIndex - firstIndex + 1)); | |
end | |
end; {framesDisplayed > 0} | |
end; | |
procedure TROIFrm.DrawXAxis; | |
var i, x: integer; | |
s: string; | |
begin | |
Canvas.Brush.Color := clBtnFace; | |
Canvas.FillRect(xAxisRect); | |
with Canvas.Pen do | |
begin | |
Color := clBlue; | |
Width := 1; | |
Style := psSolid; | |
Mode := pmCopy; | |
end; | |
for i := 0 to cXTickMarks - 1 do | |
begin | |
x := viewRect.Left + MulDiv(i, bitmapWidth - 1, cXTickMarks - 1); | |
Canvas.MoveTo(x, xAxisRect.Top); | |
Canvas.LineTo(x, xAxisRect.Top + 10); | |
end; | |
s := Format('%.2g', [xWidth / (cXTickMarks - 1)]) + ' frames / division'; | |
Canvas.Textout(ClientWidth div 2 - Canvas.TextWidth(s) div 2, xAxisRect.Bottom - 20, s); | |
end; | |
procedure TROIFrm.DrawXCursorOnBitmap; | |
var bitmapXCursor: integer; | |
begin | |
bitmapXCursor := XDataToBitmap(xCursorPos); | |
with offscreenbitmap.Canvas do | |
begin | |
Pen.Color := clYellow; | |
Pen.Mode := pmXor; | |
Pen.Style := psDot; | |
end; | |
Canvas.MoveTo(bitmapXCursor, 0); | |
Canvas.LineTo(bitmapXCursor, bitmapHeight - 1); | |
end; | |
procedure TROIFrm.DrawXCursorOnScreen; | |
var bitmapXCursor: integer; | |
rc: TRect; | |
begin | |
bitmapXCursor := XDataToBitmap(xCursorPos); | |
rc := Rect(bitmapXCursor - 1, 0, bitmapXCursor + 1, bitmapHeight - 1); | |
Canvas.CopyRect(rc, offscreenBitmap.Canvas, RectBitmapToWindow(rc)); | |
end; | |
procedure TROIFrm.DrawYAxis; | |
var i, y, tw, th: integer; | |
s: string; | |
begin | |
Canvas.Brush.Color := clBtnFace; | |
Canvas.FillRect(yAxisRect); | |
with Canvas.Pen do | |
begin | |
Color := clBlue; | |
Width := 1; | |
Style := psSolid; | |
Mode := pmCopy; | |
end; | |
for i := 0 to cYTickMarks - 1 do | |
begin | |
y := viewRect.Top + MulDiv(i, bitmapHeight - 1, cYTickMarks - 1); | |
Canvas.MoveTo(yAxisRect.Right - 10, y); | |
Canvas.LineTo(yAxisRect.Right, y); | |
s := IntToStr(yTop - Muldiv(i, yHeight - 1, cYTickMarks - 1)); | |
tw := Canvas.TextWidth(s); | |
th := Canvas.TextHeight(s); | |
Canvas.TextOut(yAxisRect.Right - tw - 15, y - th div 2, s); | |
end; | |
end; | |
procedure TROIFrm.DrawYCursorOnBitmap; | |
var bitmapYCursor: integer; | |
begin | |
bitmapYCursor := YDataToBitmap(yCursorPos); | |
with offscreenbitmap.Canvas do | |
begin | |
Pen.Color := clYellow; | |
Pen.Mode := pmXor; | |
Pen.Style := psDot; | |
end; | |
Canvas.MoveTo(0, bitmapYCursor); | |
Canvas.LineTo(bitmapWidth - 1, bitmapYCursor); | |
end; | |
procedure TROIFrm.DrawYCursorOnScreen; | |
var bitmapYCursor: integer; | |
rc: TRect; | |
begin | |
bitmapYCursor := YDataToBitmap(yCursorPos); | |
rc := Rect(0, bitmapYCursor - 1, bitmapWidth - 1, bitmapYCursor + 1); | |
Canvas.CopyRect(rc, offscreenBitmap.Canvas, RectBitmapToWindow(rc)); | |
end; | |
procedure TROIFrm.OnMagnificationChanged; | |
begin | |
RedrawOffScreen; | |
AdjustLogicalCursorPos; | |
Invalidate; | |
UpdateCursorCaptions; | |
end; | |
function TROIFrm.RectBitmapToWindow(aRect: TRect): TRect; | |
begin | |
OffsetRect(aRect, viewRect.Left, viewRect.Top); | |
Result := aRect; | |
end; | |
function TROIFrm.RectWindowToBitmap(aRect: TRect): TRect; | |
begin | |
OffsetRect(aRect, -viewRect.Left, -viewRect.Top); | |
Result := aRect; | |
end; | |
procedure TROIFrm.ResizeElements; | |
var i: integer; | |
begin | |
{rectangles} | |
cornerRect := Rect(ClientWidth - TRACK_BAR_WIDTH, 0, ClientWidth - 1, TRACK_BAR_HEIGHT - 1); | |
yAxisRect := Rect(0, 0, Y_AXIS_WIDTH - 1, ClientHeight - StatusBar1.Height - 1); | |
xAxisRect := Rect(Y_AXIS_WIDTH, ClientHeight - StatusBar1.Height - X_AXIS_HEIGHT - 1, ClientWidth, | |
ClientHeight - StatusBar1.Height - 1); | |
viewRect := Rect(Y_AXIS_WIDTH, TRACK_BAR_HEIGHT, ClientWidth - TRACK_BAR_WIDTH - 1, | |
ClientHeight - X_AXIS_HEIGHT - StatusBar1.Height - 1); | |
{bitmap and trace} | |
offscreenBitmap.Width := viewRect.Right - viewRect.Left + 1; | |
offscreenBitmap.Height := viewRect.Bottom - viewRect.Top + 1; | |
bitmapWidth := viewRect.Right - viewRect.Left + 1; | |
bitmapHeight := viewRect.Bottom - viewRect.Top + 1; | |
SetLength(trace, bitmapWidth); | |
for i := 0 to bitmapWidth - 1 do | |
begin | |
trace[i].MaxPt.x := i; | |
trace[i].MinPt.x := i; | |
end; | |
{track bars} | |
HorzTrackBar1.SetBounds(0, Y_AXIS_WIDTH, ClientWidth - TRACK_BAR_WIDTH, TRACK_BAR_HEIGHT); | |
VertTrackBar1.SetBounds(ClientWidth - TRACK_BAR_WIDTH, TRACK_BAR_HEIGHT, | |
TRACK_BAR_WIDTH, ClientHeight - TRACK_BAR_HEIGHT - StatusBar1.Height); | |
HorzTrackBar1.Min := 0; | |
HorzTrackBar1.Max := bitmapWidth - 1; | |
VertTrackBar1.Min := 0; | |
VertTrackBar1.Max := bitmapHeight - 1; | |
RedrawOffscreen; | |
end; | |
procedure TROIFrm.SetDataSize(newSize: integer); | |
begin | |
fDataSize := newSize; | |
SetLength(circDataBuffer, fDataSize); | |
SetLength(dataBuffer, fDataSize); | |
framesDisplayed := 0; | |
nextFrame := 0; | |
end; | |
procedure TROIFrm.SetPrecision(newPrecision: TPrecision); | |
begin | |
case newPrecision of | |
PREC_8_BIT: f_MAX_Y_VALUE := 127; | |
PREC_10_BIT: f_MAX_Y_VALUE := 511; | |
PREC_12_BIT: f_MAX_Y_VALUE := 2047; | |
PREC_14_BIT: f_MAX_Y_VALUE := 8191; | |
else f_MAX_Y_VALUE := 32767; | |
end; | |
end; | |
procedure TROIFrm.UpdateCursorCaptions; | |
begin | |
StatusBar1.Panels[0].Text := 'X: ' + IntToStr(xCursorPos); | |
StatusBar1.Panels[1].Text := 'Y: ' + IntToStr(yCursorPos); | |
StatusBar1.Panels[2].Text := 'rX: ' + IntToStr(xCursorPos - refXCursorPos); | |
StatusBar1.Panels[3].Text := 'rY: ' + IntToStr(YCursorPos - refYCursorPos); | |
end; | |
function TROIFrm.XBitmapToData(xBitmap: integer): integer; | |
begin | |
if framesDisplayed > 0 then | |
Result := MulDiv(bitmapWidth - 1 - xBitmap, dataSize - 1, bitmapWidth - 1) | |
else | |
Result := -1; | |
end; | |
function TROIFrm.XDataToBitmap(xData: integer): integer; | |
begin | |
Result := bitmapWidth - 1 - Muldiv(xData, bitmapWidth - 1, dataSize - 1); | |
end; | |
function TROIFrm.YBitmapToData(yBitmap: integer): integer; | |
begin | |
Result := yTop - MulDiv(yBitmap, yHeight - 1, bitmapHeight - 1); | |
end; | |
function TROIFrm.YDataToBitmap(yData: integer): integer; | |
begin | |
Result := MulDiv(- yData + yTop, bitmapHeight - 1, yHeight - 1); | |
end; | |
{****************************** FORM EVENTS ***********************************} | |
procedure TROIFrm.FormCreate(Sender: TObject); | |
begin | |
f_MAX_Y_VALUE := 2047; | |
displayMode := DM_ANALYZING; | |
offscreenBitmap := TBitmap.Create; | |
offscreenBitmap.handleType := bmDDB; | |
dataSize := 1000; {default buffer size} | |
roiThreadMutex := CreateMutex(nil, False, nil); | |
xRight := 0; | |
xWidth := dataSize; | |
yTop := f_MAX_Y_VALUE; | |
yHeight := f_MAX_Y_VALUE * 2 + 1; | |
cXTickMarks := 5; | |
cYTickMarks := 5; | |
prev_xRight := xRight; | |
prev_xWidth := xWidth; | |
prev_yTop := yTop; | |
prev_yHeight := yHeight; | |
end; | |
procedure TROIFrm.FormResize(Sender: TObject); | |
begin | |
ResizeElements; | |
AdjustCursorPos; | |
bInitialized := True; | |
Invalidate; | |
end; | |
procedure TROIFrm.FormPaint(Sender: TObject); | |
var rc, interRect: TRect; | |
begin | |
if not bInitialized then Exit; | |
rc := Canvas.ClipRect; | |
Canvas.Brush.Color := clBtnFace; | |
Canvas.Pen.Color := clBlack; | |
Canvas.Pen.Mode := pmCopy; | |
Canvas.Pen.Style := psSolid; | |
if IntersectRect(interRect, rc, cornerRect) then | |
Canvas.FillRect(cornerRect); | |
if IntersectRect(interRect, rc, xAxisRect) then | |
DrawXAxis; | |
if IntersectRect(interRect, rc, yAxisRect) then | |
DrawYAxis; | |
if IntersectRect(interRect, rc, viewRect) then | |
Canvas.CopyRect(interRect, offscreenBitmap.Canvas, RectWindowToBitmap(interRect)); | |
end; | |
procedure TROIFrm.FormDestroy(Sender: TObject); | |
begin | |
offscreenBitmap.Free; | |
if not Mainform.bClosing then | |
Mainform.ROIWndList.Remove(self); | |
CloseHandle(roiThreadMutex); | |
end; | |
{*********************************** MENUS ************************************} | |
procedure TROIFrm.XAxis1Click(Sender: TObject); | |
begin | |
ROIAxisDlg := TROIAxisDlg.Create(self); | |
try | |
ROIAxisDlg.ROIfrm := self; | |
ROIAxisDlg.PageControl1.ActivePageIndex := 0; | |
if ROIAxisDlg.ShowModal = mrOK then | |
OnMagnificationChanged; | |
finally | |
ROIAxisDlg.Free; | |
end; | |
end; | |
procedure TROIFrm.YAxis1Click(Sender: TObject); | |
begin | |
ROIAxisDlg := TROIAxisDlg.Create(self); | |
try | |
ROIAxisDlg.ROIfrm := self; | |
ROIAxisDlg.PageControl1.ActivePageIndex := 1; | |
if ROIAxisDlg.ShowModal = mrOK then | |
OnMagnificationChanged; | |
finally | |
ROIAxisDlg.Free; | |
end; | |
end; | |
procedure TROIFrm.YAxisAutoscale1Click(Sender: TObject); | |
begin | |
YAxisAutoscale1.Checked := not YAxisAutoscale1.Checked; | |
end; | |
procedure TROIFrm.XAxisFullRange1Click(Sender: TObject); | |
begin | |
xRight := 0; | |
xWidth := dataSize; | |
OnMagnificationChanged; | |
end; | |
procedure TROIFrm.YAxisFullRange1Click(Sender: TObject); | |
begin | |
yTop := f_MAX_Y_VALUE; | |
yHeight := 2 * f_MAX_Y_VALUE + 1; | |
OnMagnificationChanged; | |
end; | |
procedure TROIFrm.PreviousMagnification1Click(Sender: TObject); | |
begin | |
xRight := prev_xRight; | |
xWidth := prev_xWidth; | |
yTop := prev_yTop; | |
yHeight := prev_yHeight; | |
OnMagnificationChanged; | |
end; | |
procedure TROIFrm.SetXAxissize1Click(Sender: TObject); | |
var s: string; | |
newSize: integer; | |
begin | |
s := IntToStr(dataSize); | |
if InputQuery('Set trace size', 'Enter trace size',s) then | |
try | |
newSize := StrToInt(s); | |
if (newSize < 100) or (newSize > 10000) then | |
MessageDlg('Trace size must be between 100 and 10000', mtError, [mbOK], 0) | |
else | |
dataSize := newSize; | |
except | |
MessageDlg('Invalid numeric value', mtError, [mbOK], 0); | |
end; | |
end; | |
procedure TROIFrm.ResetCursorRelativeOrigins1Click(Sender: TObject); | |
begin | |
refXCursorPos := xCursorPos; | |
refYCursorPos := yCursorPos; | |
UpdateCursorCaptions; | |
end; | |
procedure TROIFrm.Copydatatoclipboard1Click(Sender: TObject); | |
type TCharArray = array[1..Maxint div 2] of Char; | |
var i, cPts: integer; | |
memhandle: THandle; | |
pString: ^TCharArray; | |
s1Length, stringindex: integer; | |
s1: string; | |
begin | |
if framesDisplayed > 0 then | |
try | |
Clipboard.Open; | |
Clipboard.Clear; | |
{fills string with data; 11 digits for each column} | |
if framesDisplayed < dataSize then | |
cPts := nextFrame | |
else | |
cPts := dataSize; | |
memHandle := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE or GMEM_ZEROINIT, 24 * | |
cPts + 1); | |
pString := GlobalLock(memHandle); | |
stringindex := 0; | |
for i := 0 to cPts - 1 do | |
begin | |
s1 := IntToStr(i) + TAB; | |
s1Length := Length(s1); | |
CopyMemory(@(pString^[stringIndex]), @s1[1], s1Length); | |
stringIndex := stringIndex + s1Length; {points to the next character} | |
s1 := IntToStr(dataBuffer[i]) + CR; | |
s1Length := Length(s1); | |
CopyMemory(@(pString^[stringIndex]), @s1[1], s1Length); | |
stringIndex := stringIndex + s1Length; {points to the next character} | |
end; | |
Clipboard.SetAsHandle(CF_TEXT, memHandle); | |
finally | |
Clipboard.Close; | |
end; | |
end; | |
{****************************** PUBLIC METHODS *********************************} | |
procedure TROIFrm.CopyCircData; {copies circdataBuffer into dataBuffer} | |
var i: integer; | |
begin | |
if framesDisplayed > 0 then | |
begin | |
if (framesDisplayed < dataSize) then | |
begin | |
if nextFrame > 0 then | |
for i := 0 to nextFrame - 1 do dataBuffer[i] := circdataBuffer[i]; | |
end | |
else | |
begin | |
{uncircularize data} | |
for i := nextFrame to dataSize - 1 do | |
dataBuffer[i - nextFrame] := circdataBuffer[i]; | |
if nextFrame > 0 then | |
for i := 0 to nextFrame - 1 do | |
dataBuffer[i + dataSize - nextFrame] := circdataBuffer[i]; | |
end; | |
end; | |
end; | |
procedure TROIFrm.CopyOffscreenToScreen; {forces update of the screen} | |
begin | |
Canvas.CopyRect(viewRect, offscreenBitmap.Canvas, Rect(0, 0, bitmapWidth - 1, bitmapHeight - 1)); | |
end; | |
procedure TROIFrm.OnScanningStart; {resets the circular buffer} | |
begin | |
SetXAxissize1.Enabled := False; | |
Copydatatoclipboard1.Enabled := False; | |
framesDisplayed := 0; | |
nextFrame := 0; | |
roiThread := TROIThread.Create(True); {thread does not start immediatly} | |
roiThread.FreeOnTerminate := True; | |
roiThread.roiFrm := self; | |
roiThread.Resume; | |
end; | |
procedure TROIFrm.OnScanningEnd; | |
begin | |
SetXAxissize1.Enabled := True; | |
Copydatatoclipboard1.Enabled := True; | |
end; | |
procedure TROIFrm.RedrawOffscreen; {called by the thread} | |
begin | |
{Drawing} | |
DrawBitmap; | |
{Data} | |
DrawData; | |
{Cursors} | |
DrawXCursorOnBitmap; | |
DrawYCursorOnBitmap; | |
end; | |
procedure TROIFrm.SavePrevMag; | |
begin | |
prev_xRight := xRight; | |
prev_xWidth := xWidth; | |
prev_yTop := yTop; | |
prev_yHeight := yHeight; | |
end; | |
{*********************************** EVENTS ***********************************} | |
procedure TROIFrm.HorzTrackBar1Change(Sender: TObject); | |
begin | |
if not bAdjustingCursorPos then | |
begin | |
{draw} | |
DrawYCursorOnBitmap; {erases prev cursor} | |
DrawYCursorOnScreen; {gone!} | |
yCursorPos := YBitmapToData(HorzTrackBar1.Position); | |
DrawYCursorOnBitmap; | |
DrawYCursorOnScreen; | |
UpdateCursorCaptions; | |
end; | |
end; | |
procedure TROIFrm.VertTrackBar1Change(Sender: TObject); | |
begin | |
if not bAdjustingCursorPos then | |
begin | |
{draw} | |
DrawXCursorOnBitmap; {erases prev cursor} | |
DrawXCursorOnScreen; {gone!} | |
xCursorPos := xBitmapToData(HorzTrackBar1.Position); | |
DrawXCursorOnBitmap; | |
DrawXCursorOnScreen; | |
UpdateCursorCaptions; | |
end; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit ROIAxisDlgu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
ExtCtrls, StdCtrls, Spin, ComCtrls, Buttons, ROIFrmu; | |
type | |
TROIAxisDlg = class(TForm) | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
PageControl1: TPageControl; | |
TabSheet1: TTabSheet; | |
TabSheet2: TTabSheet; | |
fromFrameEdit: TSpinEdit; | |
toFrameEdit: TSpinEdit; | |
cXTicksEdit: TSpinEdit; | |
Label1: TLabel; | |
Label2: TLabel; | |
Label3: TLabel; | |
Bevel1: TBevel; | |
Label4: TLabel; | |
FromYEdit: TSpinEdit; | |
Label5: TLabel; | |
ToYEdit: TSpinEdit; | |
Bevel2: TBevel; | |
Label6: TLabel; | |
cYTicksEdit: TSpinEdit; | |
procedure FormShow(Sender: TObject); | |
procedure BitBtn1Click(Sender: TObject); | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
ROIfrm: TROIFrm; | |
end; | |
var | |
ROIAxisDlg: TROIAxisDlg; | |
implementation | |
{$R *.DFM} | |
procedure TROIAxisDlg.FormShow(Sender: TObject); | |
begin | |
with ROIfrm do | |
begin | |
{frames are 0-based} | |
fromFrameEdit.Value := xLeft; | |
toFrameEdit.Value := xLeft + xWidth - 1; | |
cXTicksEdit.Value := cXTickMarks; | |
FromYEdit.Value := yTop - yHeight + 1; | |
ToYEdit.Value := yTop; | |
cYTicksEdit.Value := cYTickMarks; | |
end; | |
end; | |
type | |
TAxisFrmError = (AFE_NO_ERROR, AFE_FROM_FRAME, AFE_TO_FRAME, AFE_XTICKS, | |
AFE_Y_FROM, AFE_Y_TO, AFE_YTICKS, AFE_X_ORDER, AFE_Y_ORDER); | |
resourcestring | |
sInvalidFromFrame = 'Invalid "From Frame" value.'; | |
sInvalidToFrame = 'Invalid "To Frame" value.'; | |
sInvalidXTicks = 'Invalid "Number of ticks" value for the X- axis.'; | |
sInvalidYFrom = 'Invalid "From" value for the Y- axis.'; | |
sInvalidYTo = 'Invalid "To" value for the Y- axis.'; | |
sInvalidYTicks = 'Invalid "Number of ticks" value for the Y- axis.'; | |
sInvalidXOrder = 'X-Axis "From Frame" value must be inferior than the "To Frame" value.'; | |
sInvalidYOrder = 'Y-Axis "From" value must be inferior than the "To" value.'; | |
procedure TROIAxisDlg.BitBtn1Click(Sender: TObject); | |
var AxisFrmError: TAxisFrmError; | |
begin | |
AxisFrmError := AFE_NO_ERROR; | |
with ROIfrm do | |
begin | |
if (fromFrameEdit.Value < 0) or (fromFrameEdit.Value >= dataSize) then | |
AxisFrmError := AFE_FROM_FRAME; | |
if (toFrameEdit.Value < 0) or (toFrameEdit.Value >= dataSize) then | |
AxisFrmError := AFE_TO_FRAME; | |
if fromFrameEdit.Value >= toFrameEdit.Value then | |
AxisFrmError := AFE_X_ORDER; | |
if (cXTicksEdit.Value < 0) or (cXTicksEdit.Value > 10) then | |
AxisFrmError := AFE_XTICKS; | |
if (FromYEdit.Value > f_MAX_Y_VALUE) or (FromYEdit.Value < - f_MAX_Y_VALUE - 1) then | |
AxisFrmError := AFE_Y_FROM; | |
if (ToYEdit.Value > f_MAX_Y_VALUE) or (ToYEdit.Value < - f_MAX_Y_VALUE - 1) then | |
AxisFrmError := AFE_Y_TO; | |
if FromYEdit.Value >= ToYEdit.Value then | |
AxisFrmError := AFE_Y_ORDER; | |
if (cYTicksEdit.Value < 0) or (cYTicksEdit.Value > 10) then | |
AxisFrmError := AFE_YTICKS; | |
end; | |
case AxisFrmError of | |
AFE_FROM_FRAME: MessageDlg(sInvalidFromFrame, mtError, [mbOK], 0); | |
AFE_TO_FRAME: MessageDlg(sInvalidToFrame, mtError, [mbOK], 0); | |
AFE_XTICKS: MessageDlg(sInvalidXTicks, mtError, [mbOK], 0); | |
AFE_Y_FROM: MessageDlg(sInvalidYFrom, mtError, [mbOK], 0); | |
AFE_Y_TO: MessageDlg(sInvalidYTo, mtError, [mbOK], 0); | |
AFE_YTICKS: MessageDlg(sInvalidYTicks, mtError, [mbOK], 0); | |
AFE_X_ORDER: MessageDlg(sInvalidXOrder, mtError, [mbOK], 0); | |
AFE_Y_ORDER: MessageDlg(sInvalidYOrder, mtError, [mbOK], 0); | |
end; | |
if AxisFrmError = AFE_NO_ERROR then | |
with ROIfrm do | |
begin | |
SavePrevMag; | |
xLeft := fromFrameEdit.Value; | |
xWidth := toFrameEdit.Value - xLeft + 1; | |
cXTickMarks := cXTicksEdit.Value; | |
yTop := ToYEdit.Value; | |
yHeight := yTop - FromYEdit.Value + 1; | |
cYTickMarks := cYTicksEdit.Value; | |
end | |
else | |
ModalResult := mrNone; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit ROIFrmu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
Menus, Trackcur, Horzbaru, ComCtrls, MPViewu, MPFileu, ExtCtrls, Vieweru; | |
type | |
TROIFrm = class(TForm) | |
MainMenu1: TMainMenu; | |
Axis1: TMenuItem; | |
XAxis1: TMenuItem; | |
YAxis1: TMenuItem; | |
Data1: TMenuItem; | |
Copydatatoclipboard1: TMenuItem; | |
StatusBar1: TStatusBar; | |
N1: TMenuItem; | |
ResetCursorRelativeOrigins1: TMenuItem; | |
PopupMenu1: TPopupMenu; | |
ResetRelative1: TMenuItem; | |
N2: TMenuItem; | |
XAxisFullRange1: TMenuItem; | |
YAxisFullRange1: TMenuItem; | |
PreviousMagnification1: TMenuItem; | |
YAxisAutoscale1: TMenuItem; | |
CopydatatoclipboardasTEXT1: TMenuItem; | |
procedure FormResize(Sender: TObject); | |
procedure FormCreate(Sender: TObject); | |
procedure XAxis1Click(Sender: TObject); | |
procedure YAxis1Click(Sender: TObject); | |
procedure FormPaint(Sender: TObject); | |
procedure ResetCursorRelativeOrigins1Click(Sender: TObject); | |
procedure HorzTrackBar1Change(Sender: TObject); | |
procedure Copydatatoclipboard1Click(Sender: TObject); | |
procedure XAxisFullRange1Click(Sender: TObject); | |
procedure YAxisFullRange1Click(Sender: TObject); | |
procedure YAxisAutoscale1Click(Sender: TObject); | |
procedure PreviousMagnification1Click(Sender: TObject); | |
procedure VertTrackBar1Change(Sender: TObject); | |
procedure FormClose(Sender: TObject; var Action: TCloseAction); | |
procedure FormDestroy(Sender: TObject); | |
procedure CopydatatoclipboardasTEXT1Click(Sender: TObject); | |
private | |
{ Private declarations } | |
bInitialized, {prevents FormPaint before first FormResize} | |
bAdjustingCursorPos: boolean; {prevent activation of OnChange events} | |
fDataSize: integer; | |
prev_xLeft, prev_xWidth, | |
prev_yTop, prev_yHeight: integer; | |
{rectangle areas} | |
bitmapWidth, bitmapHeight: integer; | |
viewRect, | |
xAxisRect, | |
yAxisRect, | |
cornerRect: TRect; | |
xCursorPos, | |
yCursorPos, | |
refXCursorPos, | |
refYCursorPos: integer; | |
HorzTrackBar1: THorzTrackBar; | |
VertTrackBar1: TVertTrackBar; | |
procedure AdjustCursorPos; | |
procedure AdjustLogicalCursorPos; | |
procedure DrawBitmap; | |
procedure DrawData; | |
procedure DrawXCursorOnBitmap; | |
procedure DrawXCursorOnScreen; | |
procedure DrawAxis; | |
procedure DrawYCursorOnBitmap; | |
procedure DrawYCursorOnScreen; | |
procedure OnMagnificationChanged; | |
function RectBitmapToWindow(aRect: TRect): TRect; | |
function RectWindowToBitmap(aRect: TRect): TRect; | |
procedure RedrawOffScreen; | |
procedure ResizeElements; | |
procedure SetDataSize(newSize: integer); | |
procedure SetPrecision(newPrecision: TPrecision); | |
procedure UpdateCursorCaptions; | |
function XBitmapToData(xBitmap: integer): integer; | |
function XCursorDataToBitmap(xData: integer): integer; | |
function YBitmapToData(yBitmap: integer): integer; | |
function YDataToBitmap(yData: integer): integer; | |
public | |
{ Public declarations } | |
bLineProfile: boolean; | |
f_MAX_Y_VALUE: integer; | |
bDontUnregister: boolean; | |
{axis} | |
frameRate: double; {in seconds} | |
fromFrame, toFrame, | |
xLeft, xWidth, | |
yTop, yHeight: integer; {logical values} | |
cXTickMarks, cYTickMarks: integer; | |
dataBuffer: array of integer; | |
trace: TTrace; | |
offscreenBitmap: TBitmap; | |
procedure SavePrevMag; | |
procedure SaveDataToFile(bASCII: boolean; padding: integer; filename: string); | |
property dataSize: integer read fDataSize write SetDataSize; | |
property precision: TPrecision write SetPrecision; | |
end; | |
var | |
ROIFrm: TROIFrm; | |
implementation | |
{$R *.DFM} | |
uses ROIAxisDlgu, Clipbrd; | |
const | |
TRACK_BAR_WIDTH = 17; | |
TRACK_BAR_HEIGHT = 17; | |
Y_AXIS_WIDTH = 75; | |
X_AXIS_HEIGHT = 35; | |
{**************************** PRIVATE METHODS *********************************} | |
procedure TROIFrm.AdjustCursorPos; | |
begin | |
bAdjustingCursorPos := True; | |
VertTrackBar1.Position := {bitmapHeight - 1 -} Muldiv(yCursorPos - (yTop - yHeight + 1), | |
bitmapHeight - 1, yHeight - 1); | |
HorzTrackBar1.Position := Muldiv(xCursorPos - (xLeft + xWidth - 1), bitmapWidth - 1, - xWidth + 1); | |
bAdjustingCursorPos := False; | |
end; | |
procedure TROIFrm.AdjustLogicalCursorPos; | |
begin | |
xCursorPos := XBitmapToData(HorzTrackBar1.Position); | |
yCursorPos := YBitmapToData(bitmapHeight - 1 - VertTrackBar1.Position); | |
end; | |
procedure TROIFrm.DrawBitmap; | |
begin | |
with offscreenBitmap.Canvas do | |
begin | |
Brush.Color := clBlack; | |
FillRect(Rect(0, 0, bitmapWidth - 1, bitmapHeight - 1)); | |
end; | |
end; | |
procedure TROIFrm.DrawData; | |
var lastIndex, firstIndex, i, j, k, indexofnextpt, | |
dataVal, maxVal, minVal: integer; | |
bitmapY, bitmaprY: integer; | |
begin | |
lastIndex := -1; firstIndex := -1; | |
for i := 0 to bitmapWidth - 1 do {index in trace} | |
begin | |
j := XBitmapToData(i); {index in data buffer} | |
indexofnextpt := XBitmapToData(i + 1) - 1; | |
if (j >= 0) and (j < datasize) then | |
begin | |
if firstIndex = -1 then firstIndex := i; | |
lastIndex := i; | |
trace[i].MaxPt.y := dataBuffer[j]; | |
trace[i].MinPt.y := trace[i].MaxPt.y; | |
if (indexofnextPt > j) and (indexofnextPt < datasize) and | |
(j < datasize - 1) then | |
for k := j + 1 to indexofnextPt do | |
begin | |
dataVal := dataBuffer[k]; | |
if dataVal > trace[i].MaxPt.y then trace[i].MaxPt.y := dataVal; | |
if dataVal < trace[i].MinPt.y then trace[i].MinPt.y := dataVal; | |
end; | |
end; {j} | |
end; {i} | |
if (lastIndex <> -1) and (firstIndex <> -1) and (firstIndex < lastIndex) then | |
begin | |
if YAxisAutoscale1.Checked then | |
begin | |
{Autoscale} | |
maxVal := trace[firstIndex].MaxPt.y; | |
minVal := trace[firstIndex].MinPt.y; | |
{find the maximum and minimum values} | |
for i := firstIndex + 1 to lastIndex do | |
begin | |
if maxVal < trace[i].MaxPt.y then maxVal := trace[i].MaxPt.y; | |
if minVal < trace[i].MinPt.y then minVal := trace[i].MinPt.y; | |
end; | |
{at least 100 pixel difference for autoscale} | |
if maxVal >= minVal + 100 then | |
begin | |
bitmapY := YDataToBitmap(YCursorPos); | |
bitmaprY := YDataToBitmap(refYCursorPos); | |
yTop := (maxVal + minVal) div 2 + Muldiv(10, (maxVal - minVal + 1) div 2, 9); | |
yHeight := Muldiv(10, maxVal - minVal + 1, 9); | |
if yTop > f_MAX_Y_VALUE then yTop := f_MAX_Y_VALUE; | |
if yTop - yHeight < - f_MAX_Y_VALUE - 1 then | |
yHeight := f_MAX_Y_VALUE + 1 + yTop; | |
DrawAxis; | |
YCursorPos := YBitmapToData(bitmapY); | |
refYCursorPos := YBitmapToData(bitmaprY); | |
UpdateCursorCaptions; | |
end; | |
end; | |
{logical to bitmap Y} | |
for i := firstIndex to lastIndex do | |
begin | |
dataVal := YDataToBitmap(trace[i].MaxPt.y); | |
if dataVal < 0 then dataVal := 0; if dataVal >= bitmapHeight then dataVal := bitmapHeight - 1; | |
trace[i].MaxPt.y := dataVal; | |
dataVal := YDataToBitmap(trace[i].MinPt.y); | |
if dataVal < 0 then dataVal := 0; if dataVal >= bitmapHeight then dataVal := bitmapHeight - 1; | |
trace[i].MinPt.y := dataVal; | |
end; | |
with offscreenbitmap.Canvas do | |
begin | |
Pen.Color := clWhite; | |
Pen.Mode := pmCopy; | |
Pen.Style := psSolid; | |
Pen.Width := 1; | |
end; | |
Windows.Polyline(offscreenBitmap.Canvas.Handle, trace[firstIndex].MaxPt, | |
2 * (lastIndex - firstIndex + 1)); | |
end; | |
end; | |
procedure TROIFrm.DrawAxis; | |
var i, x: integer; | |
{ timebase: double;} {in s} | |
y, tw, th: integer; | |
s: string; | |
begin | |
Canvas.Brush.Color := clBtnFace; | |
Canvas.FillRect(xAxisRect); | |
Canvas.FillRect(yAxisRect); | |
with Canvas.Pen do | |
begin | |
Color := clBlue; | |
Width := 1; | |
Style := psSolid; | |
Mode := pmCopy; | |
end; | |
for i := 0 to cXTickMarks - 1 do | |
begin | |
x := viewRect.Left + MulDiv(i, bitmapWidth - 1, cXTickMarks - 1); | |
if i > 1 then x := x - 1; {adjusting for pen width} | |
Canvas.MoveTo(x, xAxisRect.Top); | |
Canvas.LineTo(x, xAxisRect.Top + 10); | |
end; | |
if not bLineProfile then | |
{ timebase := xWidth / (cXTickMarks - 1) / Mainform.configuration.frameRate;} | |
s := Format('%.2f', [xWidth / (cXTickMarks - 1)]) + ' frames / division' | |
{ + Format('%.2f', [timebase]) + ' s' } | |
else | |
s := 'Pixels'; | |
Canvas.Textout(xAxisRect.Left + (xAxisRect.Right - xAxisRect.Left) div 2 | |
- Canvas.TextWidth(s) div 2, xAxisRect.Bottom - 20, s); | |
for i := 0 to cYTickMarks - 1 do | |
begin | |
y := viewRect.Top + MulDiv(i, bitmapHeight - 1, cYTickMarks - 1); | |
Canvas.MoveTo(yAxisRect.Right - 10, y); | |
Canvas.LineTo(yAxisRect.Right, y); | |
s := IntToStr(yTop - Muldiv(i, yHeight - 1, cYTickMarks - 1)); | |
tw := Canvas.TextWidth(s); | |
th := Canvas.TextHeight(s); | |
Canvas.TextOut(yAxisRect.Right - tw - 15, y - th div 2, s); | |
end; | |
end; | |
procedure TROIFrm.DrawXCursorOnBitmap; | |
var bitmapXCursor: integer; | |
begin | |
bitmapXCursor := XCursorDataToBitmap(xCursorPos); | |
with offscreenbitmap.Canvas do | |
begin | |
Pen.Color := clYellow; | |
Pen.Mode := pmXor; | |
Pen.Style := psDot; | |
Pen.Width := 1; | |
MoveTo(bitmapXCursor, 0); | |
LineTo(bitmapXCursor, bitmapHeight - 1); | |
end; | |
end; | |
procedure TROIFrm.DrawXCursorOnScreen; | |
var bitmapXCursor: integer; | |
rc: TRect; | |
begin | |
bitmapXCursor := XCursorDataToBitmap(xCursorPos); | |
rc := Rect(bitmapXCursor - 1, 0, bitmapXCursor + 1, bitmapHeight - 1); | |
Canvas.CopyRect(RectBitmapToWindow(rc), offscreenBitmap.Canvas, rc); | |
end; | |
procedure TROIFrm.DrawYCursorOnBitmap; | |
var bitmapYCursor: integer; | |
begin | |
bitmapYCursor := YDataToBitmap(yCursorPos); | |
with offscreenbitmap.Canvas do | |
begin | |
Pen.Color := clYellow; | |
Pen.Mode := pmXor; | |
Pen.Style := psDot; | |
Pen.Width := 1; | |
MoveTo(0, bitmapYCursor); | |
LineTo(bitmapWidth - 1, bitmapYCursor); | |
end; | |
end; | |
procedure TROIFrm.DrawYCursorOnScreen; | |
var bitmapYCursor: integer; | |
rc: TRect; | |
begin | |
bitmapYCursor := YDataToBitmap(yCursorPos); | |
rc := Rect(0, bitmapYCursor - 1, bitmapWidth - 1, bitmapYCursor + 1); | |
Canvas.CopyRect(RectBitmapToWindow(rc), offscreenBitmap.Canvas, rc); | |
end; | |
procedure TROIFrm.OnMagnificationChanged; | |
begin | |
RedrawOffScreen; | |
AdjustLogicalCursorPos; | |
Invalidate; | |
UpdateCursorCaptions; | |
end; | |
function TROIFrm.RectBitmapToWindow(aRect: TRect): TRect; | |
begin | |
OffsetRect(aRect, viewRect.Left, viewRect.Top); | |
Result := aRect; | |
end; | |
function TROIFrm.RectWindowToBitmap(aRect: TRect): TRect; | |
begin | |
OffsetRect(aRect, -viewRect.Left, -viewRect.Top); | |
Result := aRect; | |
end; | |
procedure TROIFrm.RedrawOffScreen; | |
begin | |
DrawBitmap; | |
DrawData; | |
DrawXCursorOnBitmap; | |
DrawYCursorOnBitmap; | |
end; | |
procedure TROIFrm.ResizeElements; | |
var i: integer; | |
begin | |
{rectangles} | |
cornerRect := Rect(ClientWidth - TRACK_BAR_WIDTH, 0, ClientWidth - 1, TRACK_BAR_HEIGHT - 1); | |
yAxisRect := Rect(0, 0, Y_AXIS_WIDTH - 1, ClientHeight - StatusBar1.Height - 1); | |
xAxisRect := Rect(Y_AXIS_WIDTH, ClientHeight - StatusBar1.Height - X_AXIS_HEIGHT - 1, ClientWidth, | |
ClientHeight - StatusBar1.Height - 1); | |
viewRect := Rect(Y_AXIS_WIDTH + 1, TRACK_BAR_HEIGHT + 1, ClientWidth - TRACK_BAR_WIDTH, | |
ClientHeight - X_AXIS_HEIGHT - StatusBar1.Height); | |
bitmapWidth := viewRect.Right - viewRect.Left + 1; | |
bitmapHeight := viewRect.Bottom - viewRect.Top + 1; | |
offscreenBitmap.Width := bitmapWidth; | |
offscreenBitmap.Height := bitmapHeight; | |
SetLength(trace, bitmapWidth); | |
for i := 0 to bitmapWidth - 1 do | |
begin | |
trace[i].MaxPt.x := i; | |
trace[i].MinPt.x := i; | |
end; | |
HorzTrackBar1.Min := 0; | |
HorzTrackBar1.Max := bitmapWidth - 1; | |
VertTrackBar1.Min := 0; | |
VertTrackBar1.Max := bitmapHeight - 1; | |
HorzTrackBar1.SetBounds(Y_AXIS_WIDTH, 0, ClientWidth - TRACK_BAR_WIDTH - Y_AXIS_WIDTH, TRACK_BAR_HEIGHT); | |
VertTrackBar1.SetBounds(ClientWidth - TRACK_BAR_WIDTH, TRACK_BAR_HEIGHT, | |
TRACK_BAR_WIDTH, ClientHeight - TRACK_BAR_HEIGHT - StatusBar1.Height - X_AXIS_HEIGHT); | |
UpdateCursorCaptions; | |
RedrawOffscreen; | |
end; | |
procedure TROIFrm.SetDataSize(newSize: integer); | |
begin | |
fDataSize := newSize; | |
SetLength(dataBuffer, fDataSize); | |
xLeft := 0; | |
xWidth := newSize; | |
end; | |
procedure TROIFrm.SetPrecision(newPrecision: TPrecision); | |
begin | |
case newPrecision of | |
PREC_8_BIT: f_MAX_Y_VALUE := 127; | |
PREC_10_BIT: f_MAX_Y_VALUE := 511; | |
PREC_12_BIT: f_MAX_Y_VALUE := 2047; | |
PREC_14_BIT: f_MAX_Y_VALUE := 8191; | |
else f_MAX_Y_VALUE := 32767; | |
end; | |
end; | |
procedure TROIFrm.UpdateCursorCaptions; | |
begin | |
StatusBar1.Panels[0].Text := 'X: ' + IntToStr(xCursorPos); | |
StatusBar1.Panels[1].Text := 'Y: ' + IntToStr(yCursorPos); | |
StatusBar1.Panels[2].Text := 'rX: ' + IntToStr(xCursorPos - refXCursorPos); | |
StatusBar1.Panels[3].Text := 'rY: ' + IntToStr(YCursorPos - refYCursorPos); | |
end; | |
function TROIFrm.XBitmapToData(xBitmap: integer): integer; | |
begin | |
Result := MulDiv(xBitmap, xWidth - 1, bitmapWidth - 1); | |
end; | |
function TROIFrm.XCursorDataToBitmap(xData: integer): integer; | |
begin | |
Result := Muldiv(xData - xLeft, bitmapWidth - 1, xWidth - 1); | |
end; | |
function TROIFrm.YBitmapToData(yBitmap: integer): integer; | |
begin | |
Result := yTop - MulDiv(yBitmap, yHeight - 1, bitmapHeight - 1); | |
end; | |
function TROIFrm.YDataToBitmap(yData: integer): integer; | |
begin | |
Result := MulDiv(- yData + yTop, bitmapHeight - 1, yHeight - 1); | |
end; | |
{****************************** FORM EVENTS ***********************************} | |
procedure TROIFrm.FormCreate(Sender: TObject); | |
begin | |
HorzTrackBar1 := THorzTrackBar.Create(self); | |
HorzTrackBar1.Parent := self; | |
HorzTrackBar1.OnChange := HorzTrackBar1Change; | |
VertTrackBar1 := TVertTrackBar.Create(self); | |
VertTrackBar1.Parent := self; | |
VertTrackBar1.OnChange := VertTrackBar1Change; | |
f_MAX_Y_VALUE := 2047; | |
offscreenBitmap := TBitmap.Create; | |
offscreenBitmap.handleType := bmDDB; | |
xLeft := 0; | |
xWidth := dataSize; | |
yTop := f_MAX_Y_VALUE; | |
yHeight := f_MAX_Y_VALUE * 2 + 1; | |
cXTickMarks := 5; | |
cYTickMarks := 5; | |
prev_xLeft := xLeft; | |
prev_xWidth := xWidth; | |
prev_yTop := yTop; | |
prev_yHeight := yHeight; | |
end; | |
procedure TROIFrm.FormResize(Sender: TObject); | |
begin | |
ResizeElements; | |
AdjustCursorPos; | |
bInitialized := True; | |
Invalidate; | |
end; | |
procedure TROIFrm.FormPaint(Sender: TObject); | |
var rc, interRect: TRect; | |
begin | |
if not bInitialized then Exit; | |
rc := Canvas.ClipRect; | |
Canvas.Brush.Color := clBtnFace; | |
Canvas.Pen.Color := clBlack; | |
Canvas.Pen.Mode := pmCopy; | |
Canvas.Pen.Style := psSolid; | |
if IntersectRect(interRect, rc, cornerRect) then | |
Canvas.FillRect(cornerRect); | |
if IntersectRect(interRect, rc, xAxisRect) or IntersectRect(interRect, rc, yAxisRect) then | |
DrawAxis; | |
if IntersectRect(interRect, rc, viewRect) then | |
begin | |
RedrawOffscreen; | |
Canvas.CopyRect(interRect, offscreenBitmap.Canvas, RectWindowToBitmap(interRect)); | |
end; | |
end; | |
{*********************************** MENUS ************************************} | |
procedure TROIFrm.XAxis1Click(Sender: TObject); | |
begin | |
ROIAxisDlg := TROIAxisDlg.Create(self); | |
try | |
ROIAxisDlg.ROIfrm := self; | |
ROIAxisDlg.PageControl1.ActivePageIndex := 0; | |
if ROIAxisDlg.ShowModal = mrOK then | |
OnMagnificationChanged; | |
finally | |
ROIAxisDlg.Free; | |
end; | |
end; | |
procedure TROIFrm.YAxis1Click(Sender: TObject); | |
begin | |
ROIAxisDlg := TROIAxisDlg.Create(self); | |
try | |
ROIAxisDlg.ROIfrm := self; | |
ROIAxisDlg.PageControl1.ActivePageIndex := 1; | |
if ROIAxisDlg.ShowModal = mrOK then | |
OnMagnificationChanged; | |
finally | |
ROIAxisDlg.Free; | |
end; | |
end; | |
procedure TROIFrm.YAxisAutoscale1Click(Sender: TObject); | |
begin | |
YAxisAutoscale1.Checked := not YAxisAutoscale1.Checked; | |
end; | |
procedure TROIFrm.XAxisFullRange1Click(Sender: TObject); | |
begin | |
xLeft := 0; | |
xWidth := dataSize; | |
OnMagnificationChanged; | |
end; | |
procedure TROIFrm.YAxisFullRange1Click(Sender: TObject); | |
begin | |
yTop := f_MAX_Y_VALUE; | |
yHeight := 2 * (f_MAX_Y_VALUE + 1); | |
OnMagnificationChanged; | |
end; | |
procedure TROIFrm.PreviousMagnification1Click(Sender: TObject); | |
begin | |
xLeft := prev_xLeft; | |
xWidth := prev_xWidth; | |
yTop := prev_yTop; | |
yHeight := prev_yHeight; | |
OnMagnificationChanged; | |
end; | |
procedure TROIFrm.ResetCursorRelativeOrigins1Click(Sender: TObject); | |
begin | |
refXCursorPos := xCursorPos; | |
refYCursorPos := yCursorPos; | |
UpdateCursorCaptions; | |
end; | |
procedure TROIFrm.Copydatatoclipboard1Click(Sender: TObject); | |
type TCharArray = array[0..Maxint div 2] of Char; | |
var i: integer; | |
memhandle: THandle; | |
pString: ^TCharArray; | |
swLength, stringindex: integer; | |
s1: string; | |
sw: array[0..79] of WideChar; | |
begin | |
try | |
Clipboard.Open; | |
Clipboard.Clear; | |
{fills string with data; 11 digits for each column - each digit is a wide char} | |
memHandle := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE or GMEM_ZEROINIT, | |
SizeOf(WideChar) * 25 {2 columns of 11 digits + TAB + CRLF} * dataSize + 1); | |
pString := GlobalLock(memHandle); | |
stringindex := 0; | |
for i := 0 to dataSize - 1 do | |
begin | |
s1 := Format('%.6f', [(fromFrame + i)/FrameRate]) + TAB; | |
swLength := 2 * Length(s1); | |
CopyMemory(@(pString^[stringIndex]), StringToWideChar(s1, @sw, 80), swLength); | |
stringIndex := stringIndex + swLength; {points to the next character} | |
s1 := IntToStr(dataBuffer[i]) + CRLF; | |
swLength := 2 * Length(s1); | |
CopyMemory(@(pString^[stringIndex]), StringToWideChar(s1, @sw, 80), swLength); | |
stringIndex := stringIndex + swLength; {points to the next character} | |
end; | |
Clipboard.SetAsHandle(CF_UNICODETEXT, memHandle); | |
finally | |
Clipboard.Close; | |
end; | |
end; | |
{****************************** PUBLIC METHODS *********************************} | |
procedure TROIFrm.SavePrevMag; | |
begin | |
prev_xLeft := xLeft; | |
prev_xWidth := xWidth; | |
prev_yTop := yTop; | |
prev_yHeight := yHeight; | |
end; | |
procedure TROIFrm.SaveDataToFile(bASCII: boolean; padding: integer; filename: string); | |
var i, paddingIndex: integer; | |
fileStream: TFileStream; | |
swLength: integer; | |
s1: string; | |
sw: array[0..179] of WideChar; | |
begin | |
fileStream := TFileStream.Create(filename, fmCreate or fmShareExclusive); | |
try | |
fileStream.Seek(0, soFromBeginning); | |
{fills string with data; 11 digits for each column - each digit is a wide char, 2 columns} | |
{number of rows is (toFrame - fromFrame + 1) * ChDataPtsPerFrame[]} | |
{frameIndex: 0 to toFrame - fromFrame} | |
{time in s for each frame: (fromFrame + frameIndex) * FrameSize * PixelClock * 1e-6 } | |
{sampleIndex: 0 to ChDataPtsPerFrame[] - 1} | |
{for each sample: sampleIndex * FrameSize * PixelClock * 1e-6 / ChDataPtsPerFrame[]} | |
for i := 0 to dataSize - 1 do | |
for paddingIndex := 0 to padding - 1 do | |
begin | |
s1 := Format('%.6f', [(fromFrame + i + paddingIndex/padding)/FrameRate]) + TAB + IntToStr(dataBuffer[i]) + CRLF; | |
if bASCII then | |
fileStream.Write(s1[1], Length(s1)) | |
else | |
begin | |
swLength := 2 * Length(s1); {Unicode business} | |
StringToWideChar(s1, @sw, swLength + 1); | |
fileStream.Write(sw, swLength); | |
end; | |
end; | |
finally | |
fileStream.Free; | |
end; | |
end; | |
{*********************************** EVENTS ***********************************} | |
procedure TROIFrm.HorzTrackBar1Change(Sender: TObject); | |
begin | |
if not bAdjustingCursorPos then | |
begin | |
{draw} | |
DrawXCursorOnBitmap; {erases prev cursor} | |
DrawXCursorOnScreen; {gone!} | |
xCursorPos := xBitmapToData(HorzTrackBar1.Position); | |
DrawXCursorOnBitmap; | |
DrawXCursorOnScreen; | |
UpdateCursorCaptions; | |
end; | |
end; | |
procedure TROIFrm.VertTrackBar1Change(Sender: TObject); | |
begin | |
if not bAdjustingCursorPos then | |
begin | |
{draw} | |
DrawYCursorOnBitmap; {erases prev cursor} | |
DrawYCursorOnScreen; {gone!} | |
yCursorPos := yBitmapToData(vertTrackBar1.Max - vertTrackBar1.Position); | |
DrawYCursorOnBitmap; | |
DrawYCursorOnScreen; | |
UpdateCursorCaptions; | |
end; | |
end; | |
procedure TROIFrm.FormClose(Sender: TObject; var Action: TCloseAction); | |
begin | |
Action := caFree; | |
end; | |
procedure TROIFrm.FormDestroy(Sender: TObject); | |
begin | |
offscreenBitmap.Free; | |
end; | |
procedure TROIFrm.CopydatatoclipboardasTEXT1Click(Sender: TObject); | |
type TCharArray = array[0..Maxint div 2] of Char; | |
var i: integer; | |
memhandle: THandle; | |
pString: ^TCharArray; | |
swLength, stringindex: integer; | |
s1: string; | |
begin | |
try | |
Clipboard.Open; | |
Clipboard.Clear; | |
{fills string with data; 11 digits for each column - each digit is a wide char} | |
memHandle := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE or GMEM_ZEROINIT, | |
25 {2 columns of 11 digits + TAB + CRLF} * dataSize + 1); | |
pString := GlobalLock(memHandle); | |
stringindex := 0; | |
for i := 0 to dataSize - 1 do | |
begin | |
s1 := Format('%.6f', [(fromFrame + i)/FrameRate]) + TAB; | |
swLength := Length(s1); | |
CopyMemory(@(pString^[stringIndex]), @s1[1], swLength); | |
stringIndex := stringIndex + swLength; {points to the next character} | |
s1 := IntToStr(dataBuffer[i]) + CRLF; | |
swLength := Length(s1); | |
CopyMemory(@(pString^[stringIndex]), @s1[1], swLength); | |
stringIndex := stringIndex + swLength; {points to the next character} | |
end; | |
Clipboard.SetAsHandle(CF_TEXT, memHandle); | |
finally | |
Clipboard.Close; | |
end; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit StatDlgu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
ExtCtrls, StdCtrls, Mask, Buttons, MPFileu; | |
type | |
TStatDlg = class(TForm) | |
BitBtn1: TBitBtn; | |
Label1: TLabel; | |
Label2: TLabel; | |
Label3: TLabel; | |
Label4: TLabel; | |
Label5: TLabel; | |
Label6: TLabel; | |
SpeedButton1: TSpeedButton; | |
Label7: TLabel; | |
Label9: TLabel; | |
Label10: TLabel; | |
MaskEdit1: TMaskEdit; | |
MaskEdit2: TMaskEdit; | |
MaskEdit3: TMaskEdit; | |
MaskEdit4: TMaskEdit; | |
Label11: TLabel; | |
Bevel1: TBevel; | |
Bevel2: TBevel; | |
Bevel3: TBevel; | |
Label12: TLabel; | |
Label13: TLabel; | |
Label14: TLabel; | |
Bevel4: TBevel; | |
Label15: TLabel; | |
Label16: TLabel; | |
Bevel5: TBevel; | |
Label17: TLabel; | |
procedure SpeedButton1Click(Sender: TObject); | |
private | |
{ Private declarations } | |
fMPFile: TMPFile; | |
fchIndex: integer; | |
fFrameIndex: integer; | |
procedure RefreshStats; | |
public | |
{ Public declarations } | |
procedure Initialize(ampFile: TMPFile; framenumber, channelnumber: integer; | |
areaRC: TRect); | |
end; | |
var | |
StatDlg: TStatDlg; | |
implementation | |
{$R *.DFM} | |
uses MPViewu; | |
procedure TStatDlg.RefreshStats; | |
var rc: TRect; | |
x, y, value: integer; | |
begin | |
try | |
rc.Left := StrToInt(MaskEdit1.Text); | |
rc.Top := StrToInt(MaskEdit2.Text); | |
rc.Right := StrToInt(MaskEdit3.Text); | |
rc.Bottom := StrToInt(MaskEdit4.Text); | |
if (rc.Left >= 0) and (rc.Left < fMPFile.FrameWidth) and (rc.Top >= 0) and | |
(rc.Top < fMPFile.FrameHeight) and (rc.Right >= 0) and (rc.Right < fMPFile.FrameWidth) and | |
(rc.Bottom >= 0) and (rc.Bottom < fMPFile.FrameHeight) then | |
begin | |
NormalizeRect(rc); | |
value := fMPFile.GetAverage(fFrameIndex, fChIndex, rc); | |
Label11.Caption := IntToStr(value); | |
value := fMPFile.GetMax(fFrameIndex, fChIndex, rc, x, y); | |
Label12.Caption := IntToStr(value); | |
Label13.Caption := 'X = ' + IntToStr(x) + ', Y = ' + IntToStr(y); | |
value := fMPFile.GetMin(fFrameIndex, fChIndex, rc, x, y); | |
Label15.Caption := IntToStr(value); | |
Label17.Caption := 'X = ' + IntToStr(x) + ', Y = ' + IntToStr(y); | |
end | |
else | |
MessageDlg('Area Parameters Out Of Bounds.', mtError, [mbOK], 0); | |
except | |
MessageDlg('Invalid Area Parameters.', mtError, [mbOK], 0); | |
end; | |
end; | |
procedure TStatDlg.Initialize(ampFile: TMPFile; framenumber, channelnumber: integer; | |
areaRC: TRect); | |
begin | |
fMPFile := ampFile; | |
fChIndex := channelNumber; | |
fFrameIndex := frameNumber; | |
Label6.Caption := IntToStr(fChIndex); | |
MaskEdit1.Text := IntToStr(areaRC.Left); | |
MaskEdit2.Text := IntToStr(areaRC.Top); | |
MaskEdit3.Text := IntToStr(areaRC.Right); | |
MaskEdit4.Text := IntToStr(areaRC.Bottom); | |
RefreshStats; | |
end; | |
procedure TStatDlg.SpeedButton1Click(Sender: TObject); | |
begin | |
RefreshStats; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit Trackcur; | |
interface | |
uses | |
// Horzbaru declares ancestor of TVertTrackbar: declares methods to | |
// draw ticks corresponding to grid in scope or viewer | |
Windows, Messages, Classes, Graphics, Controls, Menus, ExtCtrls, | |
Horzbaru; | |
type | |
TVertTrackBar = class(TCustomTrack) | |
private | |
fMax, fMin, fPosition, fScreenPos: integer; | |
fPageSize: integer; | |
fSliding: boolean; | |
fCursorRect: TRect; | |
fCursor: TObject; | |
{in screen coordinates: | |
fMajorTickInterval: interval between major ticks > 0 | |
fFirstMajorTickPos: position of the lowest first tick mark > 0 | |
cMinorTickCount: number of minor ticks between each tick mark > 0} | |
{fMajorTickInterval, fFirstMajorTickPos, fMinorTickCount: integer;} | |
fDitherBmp, fCursorBmp, fMaskBmp, fBackgroundBmp: TBitmap; | |
fOnChange: TNotifyEvent; | |
function CursorToScreen( Value: integer): integer; | |
function ScreenToCursor( Value: integer): integer; | |
function LimitPosition( Value: integer): integer; {clips value to the control} | |
procedure SetMax( Value : Integer ); | |
procedure SetMin( Value : Integer ); | |
procedure SetPosition( Value : Integer ); | |
function GetScreenPosition: integer; | |
procedure SetScreenPosition( Value : Integer ); | |
procedure LoadThumbBitmaps; | |
procedure UpdateDitherBitmap; | |
procedure DrawTrack; | |
{ procedure DrawTicks;} | |
procedure DrawCursor; | |
procedure WMGetDlgCode( var Msg : TWMGetDlgCode ); message wm_GetDlgCode; | |
procedure CMEnabledChanged( var Msg : TMessage ); message cm_EnabledChanged; | |
protected | |
procedure Paint; override; | |
procedure Change; dynamic; | |
procedure DoEnter; override; | |
procedure DoExit; override; | |
procedure KeyDown( var Key : Word; Shift : TShiftState ); override; | |
procedure MouseDown( Button : TMouseButton; Shift : TShiftState; X, Y : Integer ); override; | |
procedure MouseMove( Shift : TShiftState; X, Y : Integer ); override; | |
procedure MouseUp( Button : TMouseButton; Shift : TShiftState; X, Y : Integer ); override; | |
public | |
constructor Create( AOwner : TComponent ); override; | |
constructor CreateInCursor( AOwner: TComponent; theCursor: TObject); | |
destructor Destroy; override; | |
{procedure SetTickPos(majorInterval, majorPos, minorCount: integer);} | |
function CursorVisible: boolean; | |
procedure SetParams(theMax, theMin, thePos: integer); | |
procedure DrawMajorTicks(pos: integer); override; | |
procedure DrawMinorTicks(pos: integer); override; | |
published | |
property ScreenPos: integer read GetScreenPosition write SetScreenPosition; | |
property Max : integer read fMax write SetMax default 2250; | |
property Min : integer read fMin write SetMin default -2250; | |
property PageSize : integer read fPageSize write fPageSize default 200; | |
property Position : integer read fPosition write SetPosition; | |
property OnChange : TNotifyEvent read fOnChange write fOnChange; | |
{ Inherited Properties & Events } | |
property Color; | |
property DragCursor; | |
property DragMode; | |
property Enabled; | |
property HelpContext; | |
property Hint; | |
property ParentShowHint; | |
property PopupMenu; | |
property ShowHint; | |
property TabOrder; | |
property TabStop default True; | |
property Visible; | |
property OnClick; | |
property OnDragDrop; | |
property OnDragOver; | |
property OnEndDrag; | |
property OnEnter; | |
property OnExit; | |
property OnKeyDown; | |
property OnKeyPress; | |
property OnKeyUp; | |
property OnMouseDown; | |
property OnMouseMove; | |
property OnMouseUp; | |
end; | |
procedure Register; | |
implementation | |
uses SysUtils {, Cursorsu, ViewData}; | |
procedure TVertTrackBar.DrawMajorTicks(pos: integer); | |
begin | |
with Canvas do | |
begin | |
Pen.Color := clBlack; | |
Pen.Width := 1; | |
MoveTo(1, pos); | |
LineTo(9, pos); | |
end; | |
end; | |
procedure TVertTrackBar.DrawMinorTicks( pos: integer); | |
begin | |
with Canvas do | |
begin | |
Pen.Color := clBlack; | |
Pen.Width := 1; | |
MoveTo(1, pos); | |
LineTo(5, pos); | |
end; | |
end; | |
function TVertTrackBar.CursorToScreen( Value: integer): integer; | |
begin | |
Result := MulDiv(Value - fMax, ClientHeight - 1, fMin - fMax); | |
if Result < 0 then Result := 0; | |
if Result >= ClientHeight then Result := ClientHeight - 1; | |
end; | |
function TVertTrackBar.ScreenToCursor( Value: integer): integer; | |
begin | |
Result := fMax - MulDiv(Value, fMax - fMin, ClientHeight - 1); | |
end; | |
function TVertTrackBar.LimitPosition( Value: integer): integer; | |
begin | |
Result :=Value; | |
if Result > fMax then Result := fMax; | |
if Result < fMin then Result := fMin; | |
end; | |
procedure TVertTrackBar.SetMax( Value : Integer ); | |
begin | |
if value <> fMax then | |
begin | |
fMax := Value; | |
if fPosition > fMax then screenPos := CursorToScreen(fMax); | |
fPageSize := (fMax - fMin) div 20; | |
Invalidate; | |
end; | |
end; | |
procedure TVertTrackBar.SetMin( Value : Integer ); | |
begin | |
if value <> fMin then | |
begin | |
fMin := Value; | |
if fPosition < fMin then screenPos := CursorToScreen(fMin); | |
fPageSize := (fMax - fMin) div 20; | |
Invalidate; | |
end; | |
end; | |
procedure TVertTrackBar.SetPosition( Value : Integer ); | |
begin | |
if value <> fPosition then | |
begin | |
fPosition := Value; | |
if csDesigning in ComponentState then | |
Invalidate | |
else | |
begin | |
{ Erase old thumb image by drawing background bitmap } | |
Canvas.Draw( fCursorRect.Left, fCursorRect.Top, FBackgroundBmp ); | |
DrawCursor; { Draw thumb at new location } | |
Change; { Trigger Change event } | |
end; | |
end; | |
end; | |
function TVertTrackBar.GetScreenPosition; | |
begin | |
Result := CursorToScreen(fPosition); | |
end; | |
procedure TVertTrackBar.SetScreenPosition( Value : Integer ); | |
begin | |
if Value < 0 then Value := 0; | |
if Value >= ClientHeight then Value := ClientHeight - 1; | |
fPosition := ScreenToCursor(Value); | |
Invalidate; | |
end; | |
procedure TVertTrackBar.LoadThumbBitmaps; | |
const | |
vCursor: PChar = 'VCURSOR'; | |
vMask: PChar = 'VMASK'; | |
begin | |
fCursorBmp.Handle := LoadBitmap(hInstance, vCursor); | |
fMaskBmp.Handle := LoadBitmap(hInstance, vMask); | |
end; | |
procedure TVertTrackBar.UpdateDitherBitmap; | |
var | |
i, j : integer; | |
begin | |
with fDitherBmp.Canvas do | |
begin | |
Brush.Color := clWhite; | |
FillRect( Rect( 0, 0, fDitherBmp.Width, fDitherBmp.Height ) ); | |
for i := 0 to 7 do | |
for j := 0 to 7 do | |
if ( i + j ) mod 2 <> 0 then | |
Pixels[ i, j ] := clBlack; | |
end; | |
end; | |
procedure TVertTrackBar.DrawTrack; | |
begin | |
Canvas.Brush.Color := clWhite; | |
if not Enabled then | |
Canvas.Brush.Bitmap := fDitherBmp; | |
Canvas.FillRect(ClientRect); | |
end; | |
{procedure TVertTrackBar.DrawTicks; | |
begin | |
with Owner as TViewer do | |
if sweepList.Count > 0 then | |
DrawYTicksOnCursorBars(self, DrawMajorTicks, DrawMinorTicks); | |
end;} | |
procedure TVertTrackBar.DrawCursor; | |
var | |
offset : integer; | |
workBmp : TBitmap; | |
workRct : TRect; | |
begin | |
fScreenPos := CursorToScreen(fPosition); | |
offset := MulDiv(height - 1, fMax - ScreenToCursor(fScreenPos), fMax - fMin); | |
fCursorRect := Rect(1, offset - 7, 16, offset + 8); | |
fBackgroundBmp.Width := 15; | |
fBackgroundBmp.Height := 15; | |
fBackgroundBmp.Canvas.CopyRect( Rect(0, 0, fCursorBmp.Width, fCursorBmp.Height), | |
Canvas, fCursorRect ); | |
workBmp := TBitmap.Create; | |
try | |
workBmp.Height := fCursorBmp.Height; | |
workBmp.Width := fCursorBmp.Width; | |
workRct := Rect( 0, 0, fCursorBmp.Width, fCursorBmp.Height); | |
workBmp.Canvas.CopyMode := cmSrcCopy; | |
workBmp.Canvas.CopyRect( WorkRct, fBackgroundBmp.Canvas, workRct ); | |
workBmp.Canvas.CopyMode := cmSrcAnd; | |
workBmp.Canvas.CopyRect( WorkRct, fMaskBmp.Canvas, WorkRct ); | |
workBmp.Canvas.CopyMode := cmSrcPaint; | |
WorkBmp.Canvas.CopyRect( WorkRct, fCursorBmp.Canvas, WorkRct ); | |
if not Enabled then | |
begin | |
WorkBmp.Canvas.Brush.Bitmap := fDitherBmp; | |
WorkBmp.Canvas.FloodFill( WorkRct.Right - 3, WorkRct.Bottom - 3, | |
clSilver, fsSurface ); | |
end; | |
Canvas.CopyRect( fCursorRect, WorkBmp.Canvas, WorkRct ); | |
finally | |
workBmp.Free; | |
end; | |
end; | |
procedure TVertTrackBar.WMGetDlgCode( var Msg : TWMGetDlgCode ); | |
begin | |
inherited; | |
Msg.Result := dlgc_WantArrows; | |
end; | |
procedure TVertTrackBar.CMEnabledChanged( var Msg : TMessage ); | |
begin | |
inherited; | |
Invalidate; | |
end; | |
procedure TVertTrackBar.Paint; | |
begin | |
with Canvas do | |
begin | |
DrawTrack; | |
DrawTicks; | |
DrawCursor; | |
end; | |
end; | |
procedure TVertTrackBar.Change; | |
begin | |
if Assigned( FOnChange ) then FOnChange( Self ); | |
end; | |
procedure TVertTrackBar.DoEnter; | |
begin | |
inherited DoEnter; | |
Refresh; | |
end; | |
procedure TVertTrackBar.DoExit; | |
begin | |
inherited DoExit; | |
Refresh; | |
end; | |
procedure TVertTrackBar.KeyDown( var Key : Word; Shift : TShiftState ); | |
begin | |
inherited KeyDown( Key, Shift ); | |
case Key of | |
vk_Prior: | |
Position := LimitPosition(fPosition + fPageSize); | |
vk_Next: | |
Position := LimitPosition(fPosition - FPageSize); | |
vk_End: | |
Position := fMin; | |
vk_Home: | |
Position := fMax; | |
vk_Left: | |
if fPosition > fMin then Position := LimitPosition(fPosition - 1); | |
vk_Up: | |
if fPosition < fMax then Position := LimitPosition(fPosition + 1); | |
vk_Right: | |
if fPosition < fMax then Position := LimitPosition(fPosition + 1); | |
vk_Down: | |
if fPosition > fMin then Position := LimitPosition(fPosition - 1); | |
$30 {VK_0}, $60 {vk_numpad0}: | |
Position := 0; | |
end; | |
end; | |
procedure TVertTrackBar.MouseDown( Button : TMouseButton; Shift : TShiftState; X, Y : Integer ); | |
var | |
ptY : integer; | |
begin | |
inherited MouseDown( Button, Shift, X, Y ); | |
SetFocus; | |
if ( Button = mbLeft ) and PtInRect( fCursorRect, Point( X, Y ) ) then | |
fSliding := True | |
else | |
begin | |
ptY := height - 1 - MulDiv(fPosition - fMin, height, fMax - fMin); | |
if Y < PtY then | |
Position := LimitPosition(fPosition + fPageSize) | |
else | |
Position := LimitPosition(FPosition - FPageSize); | |
end; | |
end; | |
procedure TVertTrackBar.MouseMove( Shift : TShiftState; X, Y : Integer ); | |
var p, h : Integer; | |
begin | |
inherited MouseMove( Shift, X, Y ); | |
if PtInRect( FCursorRect, Point( X, Y ) ) then | |
Cursor := crSizeNS | |
else | |
Cursor := crDefault; | |
if fSliding then | |
begin | |
h := Height - 7; | |
p:= MulDiv(h - y , fMax - fMin, h) + fMin; | |
if p > fMax then p := fMax; | |
if p < fMin then p := fMin; | |
Position := p; | |
end; | |
end; | |
procedure TVertTrackBar.MouseUp( Button : TMouseButton; Shift : TShiftState; X, Y : Integer ); | |
begin | |
inherited MouseUp( Button, Shift, X, Y ); | |
if ( Button = mbLeft ) then fSliding := False; | |
end; | |
constructor TVertTrackBar.CreateInCursor( AOwner: TComponent; theCursor: TObject); | |
begin | |
Create(AOwner); | |
fCursor := theCursor; | |
end; | |
constructor TVertTrackBar.Create( AOwner : TComponent ); | |
begin | |
inherited Create( AOwner ); | |
Width := 17; | |
Height := 150; | |
fMin := -2250; | |
fMax := +2250; | |
fPosition := 0; | |
fPageSize := 200; | |
fSliding := False; | |
fCursorBmp := TBitmap.Create; | |
fCursorBmp.Width := 16; | |
fCursorBmp.Height := 16; | |
fMaskBmp := TBitmap.Create; | |
fBackgroundBmp := TBitmap.Create; | |
fDitherBmp := TBitmap.Create; | |
fDitherBmp.Width := 8; | |
fDitherBmp.Height := 8; | |
UpdateDitherBitmap; | |
LoadThumbBitmaps; | |
end; | |
destructor TVertTrackBar.Destroy; | |
begin | |
fCursorBmp.Free; | |
fMaskBmp.Free; | |
fBackgroundBmp.Free; | |
fDitherBmp.Free; | |
inherited Destroy; | |
end; | |
function TVertTrackBar.CursorVisible: boolean; | |
begin | |
if (fPosition <= fMax) and (fPosition >= fMin) then Result := True else Result := False; | |
end; | |
procedure TVertTrackBar.SetParams(theMax, theMin, thePos: integer); | |
begin | |
fMax := theMax; | |
fMin := theMin; | |
fPosition := thePos; | |
fPageSize := (fMax - fMin) div 20; | |
end; | |
procedure Register; | |
begin | |
RegisterComponents( 'Samples', [TVertTrackBar] ); | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit mtransferdlgu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
StdCtrls, Spin, Buttons, ExtCtrls, MPFileu; | |
type | |
TMTransferDlg = class(TForm) | |
BitBtn1: TBitBtn; | |
BitBtn2: TBitBtn; | |
RadioButton1: TRadioButton; | |
RadioButton2: TRadioButton; | |
Label1: TLabel; | |
SpinEdit1: TSpinEdit; | |
Label3: TLabel; | |
SpinEdit2: TSpinEdit; | |
Bevel1: TBevel; | |
Label2: TLabel; | |
Edit1: TEdit; | |
Label4: TLabel; | |
SpinEdit3: TSpinEdit; | |
Label5: TLabel; | |
ListBox1: TListBox; | |
Label6: TLabel; | |
Label7: TLabel; | |
RadioButton3: TRadioButton; | |
RadioButton4: TRadioButton; | |
procedure Edit1Change(Sender: TObject); | |
private | |
{ Private declarations } | |
public | |
{ Public declarations } | |
procedure InitGUI(afile: TMPFile); | |
function SelectedCh: integer; | |
end; | |
var | |
MTransferDlg: TMTransferDlg; | |
implementation | |
{$R *.DFM} | |
procedure TMTransferDlg.Edit1Change(Sender: TObject); | |
begin | |
Label6.Caption := Edit1.Text + '_' + IntToStr(SpinEdit3.Value); | |
end; | |
procedure TMTransferDlg.InitGUI(afile: TMPFile); | |
begin | |
with afile do | |
begin | |
RadioButton1.Checked := (DefaultVideoChannel = 0); | |
RadioButton2.Checked := (DefaultVideoChannel = 1); | |
RadioButton3.Checked := (DefaultVideoChannel = 2); | |
RadioButton4.Checked := (DefaultVideoChannel = 3); | |
if VideoChCount = 1 then | |
begin | |
RadioButton1.Enabled := False; | |
RadioButton2.Enabled := False; | |
RadioButton3.Enabled := False; | |
RadioButton4.Enabled := False; | |
end | |
else | |
begin | |
RadioButton1.Enabled := ChEnabled[0]; | |
RadioButton2.Enabled := ChEnabled[1]; | |
RadioButton3.Enabled := ChEnabled[2]; | |
RadioButton4.Enabled := ChEnabled[3]; | |
end; | |
end; | |
end; | |
function TMTransferDlg.SelectedCh: integer; | |
begin | |
if RadioButton1.Checked then | |
Result := 0 | |
else if RadioButton2.Checked then | |
Result := 1 | |
else if RadioButton3.Checked then | |
Result := 2 | |
else if RadioButton4.Checked then | |
Result := 3 | |
else | |
Result := 0; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit mpviewu; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Forms, StdCtrls, COMObj, | |
ActiveX, Registry; | |
const | |
MAX_ANALOG_CH_COUNT = 2; | |
MAX_VIDEO_CH_COUNT = 2; | |
MAX_CH = 4; | |
f_MAX_Y_VALUE = 2047; | |
BASE_CLOCK = 5e-8; {50 ns base clock = 20 MHz clock frequency} | |
{the GUID for multiphoton data files} | |
GUID_MPD: TGUID = '{5BC02769-74F0-47DF-929E-2E5D3630D9B5}'; | |
CR = Chr(13); | |
TAB = Chr(9); | |
CRLF = #13#10; | |
MAX_FALSE_COLORS = 2048; | |
MAX_GRAY_LEVELS = 256; | |
DEFAULT_MAX_PIXEL_VALUE = 2047; | |
// TypeLibrary Major and minor versions for Matlab | |
MLAppMajorVersion = 1; | |
MLAppMinorVersion = 0; | |
LIBID_MLApp: TGUID = '{554F6052-79D4-11D4-B067-009027BA5F81}'; | |
IID_IMLApp: TGUID = '{669CEC92-6E22-11CF-A4D6-00A024583C19}'; | |
IID_IMLEval: TGUID = '{27BEA9CE-A20C-430F-87C2-1CC8BA31C3A8}'; | |
DIID_DIMLApp: TGUID = '{669CEC93-6E22-11CF-A4D6-00A024583C19}'; | |
DIID_DIMLEval: TGUID = '{6E813920-23FE-4D6D-91F8-56FAB06C5D13}'; | |
CLASS_MLApp_: TGUID = '{554F6053-79D4-11D4-B067-009027BA5F81}'; | |
CLASS_MLEval: TGUID = '{00854C9D-4827-4BC5-8A7D-770E696DF6A3}'; | |
slutType = 'Lut Type'; | |
type | |
int16 = smallint; | |
int32 = integer; | |
TFrameResolution = (RESOLUTION_8_BITS, RESOLUTION_12_BITS, RESOLUTION_16_BITS); | |
TChannelResolution = TFrameResolution; | |
TPrecision = (PREC_8_BIT, PREC_10_BIT, PREC_12_BIT, PREC_14_BIT, PREC_16_BIT); | |
TFullScaleVal = (pm_42V, pm_20V, pm_10V, pm_5V, pm_2V, pm_1V, pm_0_5V, pm_0_2V); | |
TInputRange = Set Of TFullScaleVal; | |
TPrefix = ( tpXENNO, tpYOCTO, tpZEPTO, tpATTO, tpFEMTO, tpPICO, tpNANO, | |
tpMICRO, tpMILLI, tpUNITY, tpKILO, tpMEGA, tpGIGA, tpTERA, tpPETA, | |
tpECTA, tpZETTA, tpYOTTA, tpXENNA, tpZERO, tpNONE ); | |
TScanMode = (SM_MOVIE, SM_STACK, SM_LINESCAN, SM_REPEAT_LINESCAN, SM_REGIONSCAN, | |
SM_FASTSTACK); | |
TRGBTripleArray = array[0..Maxint div 8] of TRGBTriple; | |
TpRGBTripleArray = ^TRGBTripleArray; | |
TColorScheme = (CS_GRAYSCALE, CS_FALSECOLORS, CS_CUSTOMLUT); | |
{*****************************************************************************} | |
{* FILES *} | |
{*****************************************************************************} | |
TFileErr = (feOK, | |
feCannotFindFile, | |
fePathNotFound, | |
feTooManyFilesOpened, | |
feAccessDenied, | |
feBadFileType, | |
feBadVersion, | |
feForceConversion, | |
feDiskFull, | |
feFileIsNotStorage, | |
feOutOfMemory, | |
feBadDiskDrive, | |
feCannotReadFile, | |
feUnknownError, | |
feBadData, | |
feUnexpectedEOF, | |
feShareViolation, | |
feInvalidHandle, | |
feFileNotAssigned, | |
feFileNotOpen, | |
feFileNotOpenForInput, | |
feFileNotOpenForOutput, | |
feInvalidInput, | |
feInvalidName, | |
feNotAMPFile, | |
feFileAlreadyOpen | |
); | |
TStorageNameErr = (sneOK, sneInvalidName, sneTooLong, sneInvalidChar, sneNumChar, | |
sneReservedName, sneAlreadyExists); | |
TBaseColorsArray = array[0..MAX_CH - 1 {channel index}, 0..2 {RGB}] of boolean; | |
TRangeColorsArray = array[0..MAX_CH - 1] of TRGBTriple; | |
TMaxPixelsArray = array[0..MAX_CH - 1] of integer; | |
//******************************** GRAPHICS ********************************* | |
TMinMaxPt = record | |
MaxPt, MinPt: TPoint; | |
end; | |
TTrace = array of TMinMaxPt; | |
TpTrace = ^TTrace; | |
//*************************** REGION OF INTEREST **************************** | |
TSimpleROI = class | |
private | |
function GetCenter: TPoint; virtual; abstract; | |
function GetPixels(pixindex: integer): TPoint; virtual; abstract; | |
function GetPixelCount: integer; virtual; abstract; | |
public | |
fchannel, fROIIndex: integer; | |
procedure Draw(aBitmap: TBitmap; xOffset: integer); virtual; abstract; | |
function PtInROI(aPt: TPoint): boolean; virtual; abstract; | |
property Channel: integer read fChannel; | |
property Center: TPoint read GetCenter; | |
property PixelCount: integer read GetPixelCount; | |
property Pixels[pixindex: integer]: TPoint read GetPixels; | |
end; | |
TRectangularROI = class(TSimpleROI) | |
private | |
function GetCenter: TPoint; override; | |
function GetPixels(pixindex: integer): TPoint; override; | |
function GetPixelCount: integer; override; | |
public | |
roiRect: TRect; | |
procedure Draw(aBitmap: TBitmap; xOffset: integer); override; | |
function PtInROI(pt: TPoint): boolean; override; | |
end; | |
TEllipticalROI = class(TSimpleROI) | |
private | |
ellipticalRegion: THandle; | |
fPixelCount: integer; | |
pixelArray: array of TPoint; | |
function GetCenter: TPoint; override; | |
function GetPixels(pixindex: integer): TPoint; override; | |
function GetPixelCount: integer; override; | |
public | |
roiRect: TRect; | |
procedure Draw(aBitmap: TBitmap; xOffset: integer); override; | |
procedure FindPixels; | |
function PtInROI(pt: TPoint): boolean; override; | |
destructor Destroy; override; | |
end; | |
TObjectROI = class(TSimpleROI) | |
private | |
ptsList: TList; | |
function GetCenter: TPoint; override; | |
function GetPixels(pixindex: integer): TPoint; override; | |
function GetPixelCount: integer; override; | |
public | |
procedure Draw(aBitmap: TBitmap; xOffset: integer); override; | |
function PtInROI(pt: TPoint): boolean; override; | |
procedure AddPt(pt: TPoint); | |
constructor Create; | |
destructor Destroy; override; | |
end; | |
TROIList = class(TList) | |
public | |
procedure AddRectangularROI(chIndex: integer; rc: TRect); | |
procedure AddEllipticalROI(chIndex: integer; rc: TRect); | |
function GetROIs(roiIndex: integer): TSimpleROI; | |
function PtInObject(aPt: TPoint): TObjectROI; | |
function ROIOfPt(chIndex: integer; aPt: TPoint): integer; | |
procedure Clear; override; | |
destructor Destroy; override; | |
property ROIs[roiIndex: integer]: TSimpleROI read GetROIs; | |
end; | |
// ============================ Registry Methods =============================== | |
function StrParse(var fullStr: string; delim: Char): string; | |
procedure SavePosToRegistry(aForm: TForm; regini: TRegistryIniFile; const section, entry: string); | |
procedure RestorePosFromRegistry(aForm: TForm; regini: TRegistryIniFile; const section, entry: string; | |
bMainForm: boolean); | |
{*****************************************************************************} | |
{* Transfer functions *} | |
{*****************************************************************************} | |
function PrefixToString(prefix: TPrefix): string; | |
function PrefixToExponent(prefix: TPrefix): integer; | |
function PrefixToFactor(prefix: TPrefix): double; | |
function ExpToPrefixString(exponent: integer): string; | |
function GetPrefixFromValue(value: double): TPrefix; | |
{*****************************************************************************} | |
{* List Box Functions *} | |
{*****************************************************************************} | |
{this procedure initializes a list box with prefixes and unit} | |
procedure FillUnitListBox(listBox: TComboBox; sUnit: string); | |
{this function returns the index of the prefix in a list box filled with prefix-unit} | |
function UnitPrefixToListBoxIndex(prefix: integer): integer; | |
function ListBoxIndexToUnitPrefix(listBoxIndex: integer): integer; | |
procedure FillInputRangeListBox(listBox: TComboBox); {fill a list box with ns, us, etc...} | |
function InputRangeToString(inputRange: TFullScaleVal): string; | |
function FullScaleToVal(fs: TFullScaleVal): double; | |
// ============================ File I/O Methods =============================== | |
function IOErrToFileErr(code: integer): TFileErr; | |
function FileErrToStr(fe: TFileErr): string; | |
function StgErrToFileErr(hr: HResult): TFileErr; | |
// ============================ Miscellaneous ================================== | |
function FindCommonRegion(start1, end1, start2, end2: integer; | |
var commonStart, commonEnd: integer): boolean; | |
procedure NormalizeRect(var rect: TRect); | |
function PrecisionToString(aPrecision: TPrecision): string; | |
function PointStrictlyInRect(const aPt: TPoint; aRect: TRect): boolean; | |
function ScanModeToString(smode: TScanMode): string; | |
procedure MakeRectFromPts(left, top, right, bottom: integer; var rectarray: array of TPoint); | |
{******************************************************************************} | |
{*} {*} | |
{*} IMPLEMENTATION {*} | |
{*} {*} | |
{******************************************************************************} | |
uses Math, inifiles, Dialogs; | |
resourcestring | |
// FILE I/O ERRORS | |
sIOErr_FileNotFound = 'File not found.'; | |
sIOErr_PathNotFound = 'Path not found.'; | |
sIOErr_TooManyOpenFiles = 'Too many open files.'; | |
sIOErr_AccessDenied = 'File access denied.'; | |
sIOErr_InvalidHandle = 'Invalid file handle.'; | |
sIOErr_NotEnoughMemory = 'Insufficient memory for this operation.'; | |
sIOErr_InvalidFileAccessCode = 'Invalid file access code.'; | |
sIOErr_InvalidData = 'Invalid data.'; | |
sIOErr_NotEnoughStorage = 'Not enough storage.'; | |
sIOErr_InvalidDrive = 'Invalid drive.'; | |
sIOErr_CannotWrite = 'Error writing to file.'; | |
sIOErr_CannotRead = 'Error reading from file.'; | |
sIOErr_SharingViolation = 'Share violation error.'; | |
sIOErr_EOF = 'Disk read error, read past end of file.'; | |
sIOErr_DiskFull = 'Disk write error, disk full.'; | |
sIOErr_FileNotAssigned = 'File not assigned.'; | |
sIOErr_NotACompoundFile = 'Invalid file.'; | |
sIOErr_InvalidName = 'Invalid file name.'; | |
sIOErr_Unexpected = 'Unexpected error.'; | |
sIOErr_InvalidFileType = 'Invalid file type.'; | |
sIOErr_InvalidVersion = 'Invalid file version.'; | |
sIOErr_FileIsNotStorage = 'The file is not a compound file.'; | |
sIOErr_BadData = 'Corrupted data in file.'; | |
sIOErr_ForceConversion = 'Forced file conversion.'; | |
sIOErr_FileNotOpen = 'File not opened.'; | |
sIOErr_FileNotOpenForInput = 'File not opened for input.'; | |
sIOErr_FileNotOpenForOutput = 'File not opened for output.'; | |
sIOErr_InvalidInput = 'Invalid input.'; | |
sIOErr_NotAMPFile = 'The file is not a MP data file.'; | |
sIOErr_FileAlreadyOpen = 'The file is already opened.'; | |
// Storage name error | |
sSNE_InvalidName = 'Invalid name.'; | |
sSNE_TooLong = 'Name too long.'; | |
sSNE_InvalidChar = 'Invalid character in name.'; | |
sSNE_NumChar = 'Invalid numerical character in name.'; | |
sSNE_ReservedName = 'Reserved name.'; | |
sSNE_AlreadyExist = 'Name already exists.'; | |
type | |
EMPConfig = class(Exception); | |
TPropSpecArray = array[0..1000] of TPropSpec; | |
TpPropSpecArray = ^TPropSpecArray; | |
TPropVariantArray = array[0..1000] of TPropVariant; | |
TpPropVariantArray = ^TPropVariantArray; | |
TStatPropStgArray = array[0..1000] of TStatPropStg; | |
TpStatPropStgArray = ^TStatPropStgArray; | |
const | |
FMTID_User_Defined_Properties: TGUID = '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}'; | |
sAlreadyLoaded = '%s' + CRLF + 'is already open.'; | |
function PrecisionToString(aPrecision: TPrecision): string; | |
begin | |
case aPrecision of | |
PREC_8_BIT: Result := '8-bit'; | |
PREC_10_BIT: Result := '10-bit'; | |
PREC_12_BIT: Result := '12-bit'; | |
PREC_14_BIT: Result := '14-bit'; | |
else Result := '16-bit'; | |
end; | |
end; | |
procedure MakeRectFromPts(left, top, right, bottom: integer; var rectarray: array of TPoint); | |
begin | |
rectarray[0].x := left; rectarray[0].y := top; | |
rectarray[1].x := right; rectarray[1].y := top; | |
rectarray[2].x := right; rectarray[2].y := bottom; | |
rectarray[3].x := left; rectarray[3].y := bottom; | |
rectarray[4].x := left; rectarray[4].y := top; | |
end; | |
// ============================ Registry Methods =============================== | |
function StrParse(var fullStr: string; delim: Char): string; | |
var delimPos: integer; | |
begin | |
delimPos := Pos(delim, fullStr); | |
if delimPos > 0 then | |
begin | |
Result := Copy(fullStr,1,Pred(delimPos)); | |
fullStr := Copy(fullStr,Succ(delimPos),Length(fullStr)); | |
end | |
else | |
Result := fullStr; | |
end; | |
procedure SavePosToRegistry(aForm: TForm; regini: TRegistryIniFile; const section, entry: string); | |
var buffer: array[0..79] of Char; | |
windowPlacement: TWindowPlacement; | |
begin | |
windowPlacement.Length := SizeOf(windowPlacement); | |
GetWindowPlacement(aForm.Handle, @windowPlacement); | |
WVSPrintf(buffer, '%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i', @windowPlacement); | |
regini.WriteString(section, entry, StrPas(buffer)); | |
end; | |
procedure RestorePosFromRegistry(aForm: TForm; regini: TRegistryIniFile; const section, entry: string; | |
bMainForm: boolean); | |
var buffer: string; | |
windowPlacement: TWindowPlacement; | |
begin | |
buffer := regini.ReadString(section, entry, ''); | |
FillChar(windowPlacement, SizeOf(windowPlacement), 0); | |
windowPlacement.Length := SizeOf(windowPlacement); | |
if buffer <> '' then | |
begin | |
StrToIntDef(StrParse(buffer, ','), 0); | |
with windowPlacement do | |
begin | |
flags := StrToInt(StrParse(buffer, ',')); | |
showCmd := StrToInt(StrParse(buffer, ',')); | |
ptMinPosition.x := StrToInt(StrParse(buffer, ',')); | |
ptMinPosition.y := StrToInt(StrParse(buffer, ',')); | |
ptMaxPosition.x := StrToInt(StrParse(buffer, ',')); | |
ptMaxPosition.y := StrToInt(StrParse(buffer, ',')); | |
rcNormalPosition.Left := StrToInt(StrParse(buffer, ',')); | |
rcNormalPosition.Top := StrToInt(StrParse(buffer, ',')); | |
rcNormalPosition.Right := StrToInt(StrParse(buffer, ',')); | |
rcNormalPosition.Bottom := StrToInt(StrParse(buffer, ',')); | |
case ShowCmd of | |
sw_showMinimized, | |
sw_showminnoactive, | |
sw_minimize: | |
aForm.WindowState := wsMinimized; | |
sw_showmaximized: | |
aForm.WindowState := wsMaximized; | |
end; | |
end; | |
SetWindowPlacement(aForm.Handle, @windowPlacement); | |
end | |
else | |
if bMainForm then | |
with windowPlacement do | |
begin | |
showCmd := SW_SHOW; | |
if not SystemParametersInfo(SPI_GETWORKAREA, 0, @rcNormalPosition, 0) then | |
rcNormalPosition := Rect(0, 0, 799, 599); | |
SetWindowPlacement(aForm.Handle, @windowPlacement); | |
end; | |
end; | |
{*****************************************************************************} | |
{* Transfer functions *} | |
{*****************************************************************************} | |
function PrefixToString(prefix: TPrefix): string; | |
begin | |
case prefix of | |
tpXENNO: Result := 'x'; | |
tpYOCTO: Result := 'y'; | |
tpZEPTO: Result := 'z'; | |
tpATTO: Result := 'a'; | |
tpFEMTO: Result := 'f'; | |
tpPICO: Result := 'p'; | |
tpNANO: Result := 'n'; | |
tpMICRO: Result := #181; | |
tpMILLI: Result := 'm'; | |
tpUNITY : Result := ''; | |
tpKILO: Result := 'k'; | |
tpMEGA: Result := 'M'; | |
tpGIGA: Result := 'G'; | |
tpTERA: Result := 'T'; | |
tpPETA: Result := 'P'; | |
tpECTA: Result := 'E'; | |
tpZETTA: Result := 'Z'; | |
tpYOTTA: Result := 'Y'; | |
tpXENNA: Result := 'X'; | |
tpNONE: Result := ''; | |
else | |
Result := ''; | |
end; | |
end; | |
function PrefixToFactor(prefix: TPrefix): double; | |
begin | |
case prefix of | |
tpXENNO: Result := 1E-27; | |
tpYOCTO: Result := 1E-24; | |
tpZEPTO: Result := 1E-21; | |
tpATTO: Result := 1E-18; | |
tpFEMTO: Result := 1E-15; | |
tpPICO: Result := 1E-12; | |
tpNANO: Result := 1E-9; | |
tpMICRO: Result := 1E-6; | |
tpMILLI: Result := 1E-3; | |
tpUNITY : Result := 1; | |
tpKILO: Result := 1E+3; | |
tpMEGA: Result := 1E+6; | |
tpGIGA: Result := 1E+9; | |
tpTERA: Result := 1E+12; | |
tpPETA: Result := 1E+15; | |
tpECTA: Result := 1E+18; | |
tpZETTA: Result := 1E+21; | |
tpYOTTA: Result := 1E+24; | |
tpXENNA: Result := 1E+27; | |
tpNONE: Result := 1; | |
else | |
Result := 1; | |
end; | |
end; | |
function PrefixToExponent(prefix: TPrefix): integer; | |
begin | |
case prefix of | |
tpXENNO: Result := -27; | |
tpYOCTO: Result := -24; | |
tpZEPTO: Result := -21; | |
tpATTO: Result := -18; | |
tpFEMTO: Result := -15; | |
tpPICO: Result := -12; | |
tpNANO: Result := -9; | |
tpMICRO: Result := -6; | |
tpMILLI: Result := -3; | |
tpUNITY : Result := 0; | |
tpKILO: Result := +3; | |
tpMEGA: Result := +6; | |
tpGIGA: Result := +9; | |
tpTERA: Result := +12; | |
tpPETA: Result := +15; | |
tpECTA: Result := +18; | |
tpZETTA: Result := +21; | |
tpYOTTA: Result := +24; | |
tpXENNA: Result := +27; | |
tpNONE: Result := 0; | |
else | |
Result := 0; | |
end; | |
end; | |
function ExpToPrefixString(exponent: integer): string; | |
begin | |
case exponent of | |
-27: Result := 'x'; | |
-24: Result := 'y'; | |
-21: Result := 'z'; | |
-18: Result := 'a'; | |
-15: Result := 'f'; | |
-12: Result := 'p'; | |
-9: Result := 'n'; | |
-6: Result := #181; | |
-3: Result := 'm'; | |
0 : Result := ''; | |
3: Result := 'k'; | |
6: Result := 'M'; | |
9: Result := 'G'; | |
12: Result := 'T'; | |
15: Result := 'P'; | |
18: Result := 'E'; | |
21: Result := 'Z'; | |
24: Result := 'Y'; | |
27: Result := 'X'; | |
else | |
Result := ''; | |
end; | |
end; | |
{This function chooses the most appropriate prefix for the value | |
if value is too small, returns tpZERO} | |
function GetPrefixFromValue(value: double): TPrefix; | |
begin | |
value := Abs(value); | |
if value <= 1E-30 then | |
Result := tpZERO | |
else if value < 1E-24 then | |
Result := tpXENNO | |
else if value < 1E-21 then | |
Result := tpYOCTO | |
else if value < 1E-18 then | |
Result := tpZEPTO | |
else if value < 1E-15 then | |
Result := tpATTO | |
else if value < 1E-12 then | |
Result := tpFEMTO | |
else if value < 1E-9 then | |
Result := tpPICO | |
else if value < 1E-6 then | |
Result := tpNANO | |
else if value < 1E-3 then | |
Result := tpMICRO | |
else if value < 1E-0 then | |
Result := tpMILLI | |
else if value < 1E+3 then | |
Result := tpUNITY | |
else if value < 1E+6 then | |
Result := tpKILO | |
else if value < 1E+9 then | |
Result := tpMEGA | |
else if value < 1E+12 then | |
Result := tpGIGA | |
else if value < 1E+15 then | |
Result := tpTERA | |
else if value < 1E+18 then | |
Result := tpPETA | |
else if value < 1E+21 then | |
Result := tpECTA | |
else if value < 1E+24 then | |
Result := tpZETTA | |
else if value < 1E+27 then | |
Result := tpYOTTA | |
else if value < 1E+30 then | |
Result := tpXENNA | |
else | |
Result := tpXENNA; | |
end; | |
{*****************************************************************************} | |
{* List Box Functions *} | |
{*****************************************************************************} | |
procedure FillUnitListBox(listBox: TComboBox; sUnit: string); | |
begin | |
with listBox, listBox.Items do | |
begin | |
Clear; | |
Add('x' + sUnit); | |
Add('y' + sUnit); | |
Add('z' + sUnit); | |
Add('a' + sUnit); | |
Add('f' + sUnit); | |
Add('p' + sUnit); | |
Add('n' + sUnit); | |
Add(#181 + sUnit); | |
Add('m' + sUnit); | |
Add(sUnit); | |
Add('k' + sUnit); | |
Add('M' + sUnit); | |
Add('G' + sUnit); | |
Add('T' + sUnit); | |
Add('P' + sUnit); | |
Add('E' + sUnit); | |
Add('Z' + sUnit); | |
Add('Y' + sUnit); | |
Add('X' + sUnit); | |
end; | |
end; | |
function UnitPrefixToListBoxIndex(prefix: integer): integer; | |
begin | |
Result := (27 + prefix) div 3; | |
end; | |
function ListBoxIndexToUnitPrefix(listBoxIndex: integer): integer; | |
begin | |
Result := listBoxIndex * 3 - 27; | |
end; | |
procedure FillTimeListBox(listBox: TComboBox); {fill a list box with ns, us, etc...} | |
begin | |
with listBox, listBox.Items do | |
begin | |
Clear; | |
Add('ns'); | |
Add(Chr(181) + 's'); | |
Add('ms'); | |
Add('s'); | |
Add('min'); | |
Add('hr'); | |
end; | |
end; | |
procedure FillInputRangeListBox(listBox: TComboBox); | |
var i: TFullScaleVal; | |
begin | |
with listBox, listBox.Items do | |
begin | |
Clear; | |
for i := pm_42V to pm_0_2V do | |
Add(InputRangeToString(i)); | |
end; | |
end; | |
function FullScaleToVal(fs: TFullScaleVal): double; | |
begin | |
case fs of | |
pm_42V: Result := 42.0; | |
pm_20V: Result := 20.0; | |
pm_10V: Result := 10.0; | |
pm_5V: Result := 5.0; | |
pm_2V: Result := 2.0; | |
pm_1V: Result := 1.0; | |
pm_0_5V: Result := 0.5; | |
pm_0_2V: Result := 0.2; | |
else | |
Result := 0; | |
end; | |
end; | |
function InputRangeToString(inputRange: TFullScaleVal): string; | |
begin | |
case inputRange of | |
pm_42V: Result := Chr(177) + '42V'; | |
pm_20V: Result := Chr(177) + '20V'; | |
pm_10V: Result := Chr(177) + '10V'; | |
pm_5V: Result := Chr(177) + '5V'; | |
pm_2V: Result := Chr(177) + '2V'; | |
pm_1V: Result := Chr(177) + '1V'; | |
pm_0_5V: Result := Chr(177) + '0.5V'; | |
pm_0_2V: Result := Chr(177) + '0.2V'; | |
else | |
Result := ''; | |
end; | |
end; | |
function ScanModeToString(smode: TScanMode): string; | |
begin | |
case smode of | |
SM_MOVIE: Result := 'Movie'; | |
SM_STACK: Result := 'Image Stack'; | |
SM_LINESCAN: Result := 'Line Scan'; | |
SM_REPEAT_LINESCAN: Result := 'Repeat Line Scan'; | |
SM_REGIONSCAN: Result := 'Region Scan'; | |
else Result := 'Fast Stack'; | |
end | |
end; | |
function IOErrToFileErr(code: integer): TFileErr; | |
begin | |
case code of | |
2: Result := feCannotFindFile; | |
3: Result := fePathNotFound; | |
4: Result := feTooManyFilesOpened; | |
5: Result := feAccessDenied; | |
6: Result := feInvalidHandle; | |
8: Result := feOutOfMemory; | |
100: Result := feUnexpectedEOF; | |
101: Result := feDiskFull; | |
102: Result := feFileNotAssigned; | |
103: Result := feFileNotOpen; | |
104: Result := feFileNotOpenForInput; | |
105: Result := feFileNotOpenForOutput; | |
106: Result := feInvalidInput; | |
else | |
Result := feUnknownError; | |
end; | |
end; | |
function FileErrToStr(fe: TFileErr): string; | |
begin | |
case fe of | |
feCannotFindFile: Result := sIOErr_FileNotFound; | |
fePathNotFound: Result := sIOErr_PathNotFound; | |
feTooManyFilesOpened: Result := sIOErr_TooManyOpenFiles; | |
feAccessDenied: Result := sIOErr_AccessDenied; | |
feBadFileType: Result := sIOErr_InvalidFileType; | |
feBadVersion: Result := sIOErr_InvalidVersion; | |
feForceConversion: Result := sIOErr_ForceConversion; | |
feDiskFull: Result := sIOErr_DiskFull; | |
feFileIsNotStorage: Result := sIOErr_FileIsNotStorage; | |
feOutOfMemory: Result := sIOErr_NotEnoughMemory; | |
feBadDiskDrive: Result := sIOErr_InvalidDrive; | |
feCannotReadFile: Result := sIOErr_CannotRead; | |
feUnknownError: Result := sIOErr_Unexpected; | |
feBadData: Result := sIOErr_BadData; | |
feUnexpectedEOF: Result := sIOErr_EOF; | |
feShareViolation: Result := sIOErr_SharingViolation; | |
feInvalidHandle: Result := sIOErr_InvalidHandle; | |
feFileNotAssigned: Result := sIOErr_FileNotAssigned; | |
feFileNotOpen: Result := sIOErr_FileNotOpen; | |
feFileNotOpenForInput: Result := sIOErr_FileNotOpenForInput; | |
feFileNotOpenForOutput: Result := sIOErr_FileNotOpenForOutput; | |
feInvalidInput: Result := sIOErr_InvalidInput; | |
feInvalidName: Result := sIOErr_InvalidName; | |
feNotAMPFile: Result := sIOErr_NotAMPFile; | |
feFileAlreadyOpen: Result := sIOErr_FileAlreadyOpen; | |
else | |
Result := sIOErr_Unexpected; | |
end; | |
end; | |
// ***************************************************************************** | |
// | |
// ROI Methods | |
// | |
// ***************************************************************************** | |
// *************************** Rectangular ROI ********************************* | |
function TRectangularROI.GetCenter: TPoint; | |
begin | |
Result.x := (roiRect.Right + roiRect.Left) div 2; | |
Result.y := (roiRect.Bottom + roiRect.Top) div 2; | |
end; | |
function TRectangularROI.GetPixels(pixindex: integer): TPoint; | |
var rWidth, yOffset: integer; | |
begin | |
rWidth := roiRect.Right - roiRect.Left + 1; | |
yOffset := pixIndex div rWidth; | |
Result.x := roiRect.Left + pixindex - yOffset * rWidth; | |
Result.y := roiRect.Top + yOffset; | |
end; | |
function TRectangularROI.GetPixelCount: integer; | |
begin | |
Result := (roiRect.Right - roiRect.Left + 1) * (roiRect.Bottom - roiRect.Top + 1); | |
end; | |
procedure TRectangularROI.Draw(aBitmap: TBitmap; xOffset: integer); | |
{var s: string; | |
sWidth, sHeight: integer;} | |
begin | |
if fChannel = 0 then xOffset := 0; | |
with aBitmap.Canvas do | |
begin | |
Pen.Color := clWhite; | |
Pen.Style := psDot; | |
Pen.Width := 1; | |
Pen.Mode := pmCopy; | |
Polyline([Point(roiRect.Left + xOffset, roiRect.Top), | |
Point(roiRect.Right + xOffset, roiRect.Top), | |
Point(roiRect.Right + xOffset, roiRect.Bottom), | |
Point(roiRect.Left + xOffset, roiRect.Bottom), | |
Point(roiRect.Left + xOffset, roiRect.Top)]); | |
{ TextFlags := 0; | |
Font.Name := 'Arial'; | |
Font.Color := clWhite; | |
Font.Size := 10; | |
s := IntToStr(fROIIndex); | |
sWidth := TextWidth(s); | |
sHeight := TextHeight(s); | |
TextOut(Center.x + xOffset - sWidth div 2, Center.y - sHeight div 2, s);} | |
end; | |
end; | |
function TRectangularROI.PtInROI(pt: TPoint): boolean; | |
begin | |
Result := PointStrictlyInRect(pt, roiRect); | |
end; | |
type TPPoint = ^TPoint; | |
function TObjectROI.GetCenter: TPoint; | |
var i: integer; | |
ppt: TPPoint; | |
begin | |
Result.x := 0; | |
Result.y := 0; | |
if ptsList.Count > 0 then | |
begin | |
for i := 0 to ptsList.Count - 1 do | |
begin | |
ppt := TPPoint(ptsList.Items[i]); | |
Result.x := Result.x + ppt^.x; | |
Result.y := Result.y + ppt^.y; | |
end; | |
Result.x := Result.x div ptsList.Count; | |
Result.y := Result.y div ptsList.Count; | |
end; | |
end; | |
// *************************** Elliptical ROI ********************************* | |
function TEllipticalROI.GetCenter: TPoint; | |
begin | |
Result.x := (roiRect.Right + roiRect.Left) div 2; | |
Result.y := (roiRect.Bottom + roiRect.Top) div 2; | |
end; | |
function TEllipticalROI.GetPixels(pixindex: integer): TPoint; | |
begin | |
if pixindex < PixelCount then | |
Result := pixelArray[pixindex] | |
else | |
Result := Point(0, 0); | |
end; | |
function TEllipticalROI.GetPixelCount: integer; | |
begin | |
Result := fPixelCount; | |
end; | |
procedure TEllipticalROI.FindPixels; | |
var i, j, nextPt: integer; | |
begin | |
ellipticalRegion := CreateEllipticRgnIndirect(roiRect); | |
fPixelCount := 0; | |
for i := roiRect.Top to roiRect.Bottom do | |
for j := roiRect.Left to roiRect.Right do | |
if PtInRegion(ellipticalRegion, j, i) then | |
fPixelCount := fPixelCount + 1; | |
SetLength(pixelArray, fPixelCount); | |
nextPt := 0; | |
for i := roiRect.Top to roiRect.Bottom do | |
for j := roiRect.Left to roiRect.Right do | |
if PtInRegion(ellipticalRegion, j, i) then | |
begin | |
pixelArray[nextPt] := Point(j, i); | |
nextPt := nextPt + 1; | |
end; | |
end; | |
procedure TEllipticalROI.Draw(aBitmap: TBitmap; xOffset: integer); | |
begin | |
if fChannel = 0 then xOffset := 0; | |
with aBitmap.Canvas do | |
begin | |
Pen.Color := clWhite; | |
Pen.Style := psDot; | |
Pen.Width := 1; | |
Pen.Mode := pmCopy; | |
Arc(roiRect.Left + xOffset, | |
roiRect.Top, | |
roiRect.Right + xOffset, | |
roiRect.Bottom, | |
roiRect.Left + xOffset, | |
roiRect.Top, | |
roiRect.Left + xOffset, | |
roiRect.Top); | |
end; | |
end; | |
function TEllipticalROI.PtInROI(pt: TPoint): boolean; | |
begin | |
Result := PtInRegion(ellipticalRegion, pt.x, pt.y); | |
end; | |
destructor TEllipticalROI.Destroy; | |
begin | |
DeleteObject(ellipticalRegion); | |
inherited Destroy; | |
end; | |
// *************************** Object ROI ********************************* | |
function TObjectROI.GetPixels(pixindex: integer): TPoint; | |
var ppt: TPPoint; | |
begin | |
ppt := TPPoint(ptsList.Items[pixindex]); | |
Result.x := ppt^.x; | |
Result.y := ppt^.y; | |
end; | |
function TObjectROI.GetPixelCount: integer; | |
begin | |
Result := ptsList.Count; | |
end; | |
procedure TObjectROI.Draw(aBitmap: TBitmap; xOffset: integer); | |
var { s: string; | |
sWidth, sHeight: integer;} | |
pLine: TpRGBTripleArray; | |
pt : TPoint; | |
pPixel : ^TRGBTriple; | |
i: integer; | |
begin | |
if fChannel = 0 then xOffset := 0; | |
if ptsList.Count < 0 then Exit; | |
for i := 0 to PixelCount - 1 do | |
begin | |
pt := Pixels[i]; | |
pLine := aBitmap.ScanLine[pt.y]; | |
pPixel := @pLine[xOffset + pt.x]; | |
pPixel^.rgbtBlue := 255; | |
pPixel^.rgbtGreen := 255; | |
pPixel^.rgbtRed := 255; | |
end; | |
{ with aBitmap.Canvas do | |
begin | |
Font.Name := 'Arial'; | |
Font.Color := clBlack; | |
Font.Size := 10; | |
s := IntToStr(fROIIndex); | |
sWidth := TextWidth(s); | |
sHeight := TextHeight(s); | |
TextOut(Center.x + xOffset - sWidth div 2, Center.y - sHeight div 2, s); | |
end; } | |
end; | |
function TObjectROI.PtInROI(pt: TPoint): boolean; | |
var i: integer; | |
ppt: TPPoint; | |
begin | |
Result := False; | |
i := 0; | |
if ptsList.Count > 0 then | |
while not Result and (i < ptsList.Count) do | |
begin | |
ppt := TPPoint(ptsList.Items[i]); | |
if (ppt^.x = pt.x) and (ppt^.y = pt.y) then | |
Result := True | |
else | |
i := i + 1; | |
end; | |
end; | |
procedure TObjectROI.AddPt(pt: TPoint); | |
var ppt: TPPoint; | |
begin | |
GetMem(ppt, SizeOf(TPoint)); | |
ppt^.x := pt.x; | |
ppt^.y := pt.y; | |
ptsList.Add(ppt); | |
end; | |
constructor TObjectROI.Create; | |
begin | |
ptsList := TList.Create; | |
ptsList.Capacity := 1000; | |
end; | |
destructor TObjectROI.Destroy; | |
var i: integer; | |
begin | |
if ptsList.Count >= 0 then | |
for i := 0 to ptsList.Count - 1 do | |
Freemem(ptsList.Items[i], SizeOf(TPoint)); | |
ptsList.Free; | |
inherited Destroy; | |
end; | |
procedure TROIList.AddRectangularROI(chIndex: integer; rc: TRect); | |
var aRectROI: TRectangularROI; | |
begin | |
NormalizeRect(rc); | |
aRectROI := TRectangularROI.Create; | |
aRectROI.fchannel := chIndex; | |
aRectROI.fROIIndex := Count + 1; | |
aRectROI.roiRect := rc; | |
Add(aRectROI); | |
end; | |
procedure TROIList.AddEllipticalROI(chIndex: integer; rc: TRect); | |
var aEllROI: TEllipticalROI; | |
begin | |
NormalizeRect(rc); | |
aEllROI := TEllipticalROI.Create; | |
aEllROI.fchannel := chIndex; | |
aEllROI.fROIIndex := Count + 1; | |
aEllROI.roiRect := rc; | |
aEllROI.FindPixels; {populates the array of pixels} | |
Add(aEllROI); | |
end; | |
function TROIList.GetROIs(roiIndex: integer): TSimpleROI; | |
begin | |
Result := TSimpleROI(Items[roiIndex]); | |
end; | |
function TROIList.PtInObject(aPt: TPoint): TObjectROI; | |
var i: integer; | |
begin | |
Result := nil; | |
if Count> 0 then | |
for i := 0 to Count - 1 do | |
if ROIs[i] is TObjectROI then | |
if ROIs[i].PtInROI(aPt) then | |
Result := TObjectROI(ROIs[i]); | |
end; | |
function TROIList.ROIOfPt(chIndex: integer; aPt: TPoint): integer; | |
var i: integer; | |
begin | |
Result := -1; i := 0; | |
while (i < Count) and (Result = -1) do | |
begin | |
if (ROIs[i].fchannel = chIndex) and ROIs[i].PtInROI(aPt) then | |
Result := i | |
else | |
i := i + 1; | |
end; | |
end; | |
procedure TROIList.Clear; | |
var i: integer; | |
begin | |
if Count > 0 then | |
for i := 0 to Count - 1 do | |
ROIs[i].Free; | |
inherited Clear; | |
end; | |
destructor TROIList.Destroy; | |
begin | |
Clear; | |
Inherited Destroy; | |
end; | |
function FindCommonRegion(start1, end1, start2, end2: integer; | |
var commonStart, commonEnd: integer): boolean; | |
begin | |
{make sure that end1 <= start1} | |
if start1 > end1 then | |
begin | |
commonStart := start1; | |
start1 := end1; | |
end1 := commonStart; | |
end; | |
if start2 > end2 then | |
begin | |
commonStart := start2; | |
start2 := end2; | |
end2 := commonStart; | |
end; | |
if start1 > start2 then | |
begin | |
commonStart := start1; | |
commonEnd := end1; | |
// start1 := start2; no need | |
end1 := end2; | |
start2 := commonStart; | |
end2 := commonEnd; | |
end; | |
if start2 > end1 then | |
Result := False | |
else | |
begin | |
commonStart := start2; | |
if end2 <= end1 then | |
commonEnd := end2 | |
else | |
commonEnd := end1; | |
Result := True; | |
end; | |
end; | |
procedure NormalizeRect(var rect: TRect); | |
var i: integer; | |
begin | |
if rect.Left > rect.Right then | |
begin | |
i := rect.Left; | |
rect.Left := rect.Right; | |
rect.Right := i; | |
end; | |
if rect.Top > rect.Bottom then | |
begin | |
i := rect.Top; | |
rect.Top := rect.Bottom; | |
rect.Bottom := i; | |
end; | |
end; | |
function StgErrToFileErr(hr: HResult): TFileErr; | |
begin | |
{if integer(hr) = STG_E_INVALIDFUNCTION then | |
else} if integer(hr) = STG_E_FILENOTFOUND then | |
Result := feCannotFindFile | |
else if integer(hr) = STG_E_PATHNOTFOUND then | |
Result := fePathNotFound | |
else if integer(hr) = STG_E_TOOMANYOPENFILES then | |
Result := feTooManyFilesOpened | |
else if integer(hr) = STG_E_ACCESSDENIED then | |
Result := feAccessDenied | |
{ else if integer(hr) = STG_E_INVALIDHANDLE then | |
Result := ;} | |
else if integer(hr) = STG_E_INSUFFICIENTMEMORY then | |
Result := feOutOfMemory | |
else if integer(hr) = STG_E_INVALIDPOINTER then | |
Result := feBadData | |
{ else if integer(hr) = STG_E_NOMOREFILES then | |
Result := ;} | |
else if integer(hr) = STG_E_DISKISWRITEPROTECTED then | |
Result := feCannotReadFile | |
else if integer(hr) = STG_E_SEEKERROR then | |
Result := feCannotReadFile | |
else if integer(hr) = STG_E_WRITEFAULT then | |
Result := feUnexpectedEOF | |
else if integer(hr) = STG_E_READFAULT then | |
Result := feCannotReadFile | |
else if integer(hr) = STG_E_SHAREVIOLATION then | |
Result := feShareViolation | |
{ else if integer(hr) = STG_E_LOCKVIOLATION then | |
Result := ; | |
else if integer(hr) = STG_E_FILEALREADYEXISTS then | |
Result := ; | |
else if integer(hr) = STG_E_INVALIDPARAMETER then | |
Result := ;} | |
else if integer(hr) = STG_E_MEDIUMFULL then | |
Result := feDiskFull | |
{ else if integer(hr) = STG_E_ABNORMALAPIEXIT then | |
Result := ; | |
else if integer(hr) = STG_E_INVALIDHEADER then | |
Result := ;} | |
else if integer(hr) = STG_E_INVALIDNAME then | |
Result := feInvalidName | |
else if integer(hr) = STG_E_UNKNOWN then | |
Result := feUnknownError | |
{ else if integer(hr) = STG_E_UNIMPLEMENTEDFUNCTION then | |
Result := ; | |
else if integer(hr) = STG_E_INVALIDFLAG then | |
Result := ;} | |
else | |
Result := feUnknownError; | |
end; | |
function PointStrictlyInRect(const aPt: TPoint; aRect: TRect): boolean; | |
begin | |
NormalizeRect(aRect); | |
if (aPt.X >= aRect.Left) and (aPt.X <= aRect.Right) and | |
(aPt.Y >= aRect.Top) and (aPt.Y <= aRect.Bottom) then | |
Result := True | |
else | |
Result := False; | |
end; | |
end. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unit vieweru; | |
interface | |
uses | |
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, | |
Menus, ImgList, ToolWin, ComCtrls, ExtCtrls, mpviewu, mpfileu; | |
type | |
TMouseAction = (maNormal, maRectangularROI, maEllipticROI, maLineProfile, maStats); | |
TViewerFrm = class(TForm) | |
StatusBar1: TStatusBar; | |
ImageList1: TImageList; | |
MainMenu1: TMainMenu; | |
Frame1: TMenuItem; | |
NextFrame1: TMenuItem; | |
PrevFrame1: TMenuItem; | |
N1: TMenuItem; | |
FastForward1: TMenuItem; | |
FastReverse1: TMenuItem; | |
N2: TMenuItem; | |
FirstFrame1: TMenuItem; | |
LastFrame1: TMenuItem; | |
GotoFrame1: TMenuItem; | |
ROI1: TMenuItem; | |
Zoom1: TMenuItem; | |
Increasezoom1: TMenuItem; | |
DecreaseZoom1: TMenuItem; | |
Grayscale1: TMenuItem; | |
FalseColors1: TMenuItem; | |
N3: TMenuItem; | |
CreateProjection1: TMenuItem; | |
CopyFrames1: TMenuItem; | |
Stop1: TMenuItem; | |
Panel1: TPanel; | |
ToolBar1: TToolBar; | |
ToolButton1: TToolButton; | |
ToolButton2: TToolButton; | |
ToolButton3: TToolButton; | |
ToolButton4: TToolButton; | |
ToolButton5: TToolButton; | |
ToolButton6: TToolButton; | |
ToolButton7: TToolButton; | |
ToolButton8: TToolButton; | |
SaveFrameasBitmap1: TMenuItem; | |
MakeAVIMovie1: TMenuItem; | |
N5: TMenuItem; | |
SubtractwithFrame1: TMenuItem; | |
N6: TMenuItem; | |
Comments1: TMenuItem; | |
N7: TMenuItem; | |
NewFrameViewer1: TMenuItem; | |
CopyFrames2: TMenuItem; | |
N8: TMenuItem; | |
SaveDialog1: TSaveDialog; | |
GammaCorrection1: TMenuItem; | |
N9: TMenuItem; | |
AverageFrames1: TMenuItem; | |
ProjectFrameonYaxis1: TMenuItem; | |
ProjectFramesonXaxis1: TMenuItem; | |
Objects1: TMenuItem; | |
FindObjects1: TMenuItem; | |
DeleteallObjects1: TMenuItem; | |
PlotROIofObjects1: TMenuItem; | |
CreateRectangularROI1: TMenuItem; | |
CreateEllipticalROI1: TMenuItem; | |
HideROIs1: TMenuItem; | |
N4: TMenuItem; | |
N10: TMenuItem; | |
N11: TMenuItem; | |
CreateLineProfile1: TMenuItem; | |
ToolButton9: TToolButton; | |
AutomaticBackgroundCorrection1: TMenuItem; | |
AreaStats1: TMenuItem; | |
ExportFramesasamultipageTIFFfile1: TMenuItem; | |
PaintBox1: TPaintBox; | |
CustomColors1: TMenuItem; | |
N12: TMenuItem; | |
CustomColorsLookupTable1: TMenuItem; | |
N13: TMenuItem; | |
BinaryFrameOperations1: TMenuItem; | |
N14: TMenuItem; | |
OverlayCh1onCh21: TMenuItem; | |
OverlayCh2onCh31: TMenuItem; | |
procedure FormActivate(Sender: TObject); | |
procedure FormDeactivate(Sender: TObject); | |
procedure FormClose(Sender: TObject; var Action: TCloseAction); | |
procedure FormCreate(Sender: TObject); | |
procedure FormDestroy(Sender: TObject); | |
procedure ToolButton2Click(Sender: TObject); | |
procedure ToolButton4Click(Sender: TObject); | |
procedure ToolButton3Click(Sender: TObject); | |
procedure ToolButton1Click(Sender: TObject); | |
procedure ToolButton5Click(Sender: TObject); | |
procedure FirstFrame1Click(Sender: TObject); | |
procedure LastFrame1Click(Sender: TObject); | |
procedure GotoFrame1Click(Sender: TObject); | |
procedure Comments1Click(Sender: TObject); | |
procedure Grayscale1Click(Sender: TObject); | |
procedure Increasezoom1Click(Sender: TObject); | |
procedure DecreaseZoom1Click(Sender: TObject); | |
procedure NewFrameViewer1Click(Sender: TObject); | |
procedure SaveFrameasBitmap1Click(Sender: TObject); | |
procedure FormPaint(Sender: TObject); | |
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, | |
Y: Integer); | |
procedure Gammacorrection1Click(Sender: TObject); | |
procedure CopyFrames2Click(Sender: TObject); | |
procedure AverageFrames1Click(Sender: TObject); | |
procedure CreateProjection1Click(Sender: TObject); | |
procedure ProjectFrameonYaxis1Click(Sender: TObject); | |
procedure ProjectFramesonXaxis1Click(Sender: TObject); | |
procedure SubtractwithFrame1Click(Sender: TObject); | |
procedure DeleteallROIs1Click(Sender: TObject); | |
procedure MakeAVIMovie1Click(Sender: TObject); | |
procedure DeleteallObjects1Click(Sender: TObject); | |
procedure HideROIs1Click(Sender: TObject); | |
procedure CreateRectangularROI1Click(Sender: TObject); | |
procedure CreateEllipticalROI1Click(Sender: TObject); | |
procedure FindObjects1Click(Sender: TObject); | |
procedure PlotROIofObjects1Click(Sender: TObject); | |
procedure FormMouseDown(Sender: TObject; Button: TMouseButton; | |
Shift: TShiftState; X, Y: Integer); | |
procedure FormMouseUp(Sender: TObject; Button: TMouseButton; | |
Shift: TShiftState; X, Y: Integer); | |
procedure FormDblClick(Sender: TObject); | |
procedure CreateLineProfile1Click(Sender: TObject); | |
procedure CopyFrames1Click(Sender: TObject); | |
procedure AutomaticBackgroundCorrection1Click(Sender: TObject); | |
procedure AreaStats1Click(Sender: TObject); | |
procedure ExportFramesasamultipageTIFFfile1Click(Sender: TObject); | |
procedure CustomColors1Click(Sender: TObject); | |
procedure FalseColors1Click(Sender: TObject); | |
procedure CustomColorsLookupTable1Click(Sender: TObject); | |
procedure PaintBox1Paint(Sender: TObject); | |
procedure BinaryFrameOperations1Click(Sender: TObject); | |
procedure OverlayCh1onCh21Click(Sender: TObject); | |
procedure OverlayCh2onCh31Click(Sender: TObject); | |
private | |
{ Private declarations } | |
roiPt: TPoint; | |
colorScheme: TColorScheme; | |
chRect, bitmapChRect: array[0..MAX_CH - 1] of TRect; | |
frameBitmap: TBitmap; | |
fCurrentFrameIndex: integer; | |
fZoomIndex: integer; | |
currentChannel, anchorX, anchorY, prevX, prevY: integer; | |
mouseAction: TMouseAction; | |
ROIList: TROIList; | |
procedure AdjustWindowSize; | |
function CheckNoFrame: boolean; | |
procedure DrawFrame; | |
procedure GetChRect; | |
procedure ExportToMatlab(chIndex, fromFrame, toFrame: integer; | |
frameName: string; startingIndex: integer; workspace: string); | |
procedure MakeColorScale; | |
procedure OnNewFrame; | |
procedure SelectROIPlot(bAllROIs: boolean; roiIndex: integer); | |
procedure SetLUTColors; | |
procedure PlotLineProfile(chIndex: integer; rc: TRect); | |
procedure PlotROI(roiIndex, fromFrame, toFrame: integer); | |
procedure SetCurrentFrameIndex(newIndex: integer); | |
function WindowToChannel(X, Y: integer; var retChannel: integer): boolean; | |
function WindowToFrameX(chIndex, xVal: integer): integer; | |
function WindowToFrameY(yVal: integer): integer; | |
public | |
{ Public declarations } | |
mpFile: TMPFile; | |
procedure Initialize(thempFile: TMPFile; viewerIndex: integer); | |
property CurrentFrameIndex: integer read fCurrentFrameIndex write SetCurrentFrameIndex; | |
end; | |
var | |
ViewerFrm: TViewerFrm; | |
implementation | |
{$R *.DFM} | |
uses Mainfrm, gammafrmu, opframedlgu, DetectROIDlgu, PlotROIDlgu, | |
AVIOptDlgu, ROIFrmu, mtransferdlgu, ActiveX, StatDlgu, lutdlgu, binfrm | |
{, Variants}; | |
{-------------------------------- PRIVATE -------------------------------------} | |
procedure TViewerFrm.AdjustWindowSize; | |
var newWidth, newHeight: integer; | |
begin | |
if mpFile = nil then Exit; | |
{just in case width and height suddenly changed as caused by mpFile.StackX or mpFile.StackY} | |
newWidth := mpFile.VideoChCount * mpFile.FrameWidth + mpFile.VideoChCount - 1; | |
newHeight := mpFile.FrameHeight; | |
if (frameBitmap.Width <> newWidth) or (frameBitmap.Height <> newHeight) then | |
begin | |
frameBitmap.Width := newWidth; | |
frameBitmap.Height := newHeight; | |
end; | |
GetChRect; | |
if chRect[MAX_CH - 1].Right - chRect[0].Left + PaintBox1.Width + 1 > 500 then | |
ClientWidth := chRect[MAX_CH - 1].Right - chRect[0].Left + PaintBox1.Width + 1 | |
else | |
ClientWidth := 500; | |
if Panel1.Height + StatusBar1.Height + fZoomIndex * mpFile.FrameHeight > 500 then | |
ClientHeight := Panel1.Height + StatusBar1.Height + fZoomIndex * mpFile.FrameHeight | |
else | |
ClientHeight := 500; | |
end; | |
function TViewerFrm.CheckNoFrame: boolean; | |
begin | |
if (mpFile = nil) or (mpFile.FrameCount = 0) then | |
begin | |
Result := True; | |
MessageDlg( 'Operation not possible.' + CRLF + | |
'Workspace has no frame.', mtInformation, [mbOK], 0); | |
end | |
else | |
Result := False; | |
end; | |
type TBitmapLine = array[0..Maxint div 8] of TRGBTriple; | |
TpBitmapLine = ^TBitmapLine; | |
procedure TViewerFrm.DrawFrame; | |
var i, j, k, l, m, pixelValue, pixelXOffset, maxPixValue: integer; | |
pLine : TpBitmapLine; | |
pixel0, pixel1: TRGBTriple; | |
const RGB_GREEN: TRGBTriple = (rgbtBlue: 0; rgbtGreen: 255; rgbtRed: 0); | |
RGB_BLACK: TRGBTriple = (rgbtBlue: 0; rgbtGreen: 255; rgbtRed: 0); | |
begin | |
{separation line between channels} | |
with mpFile, frameBitmap, frameBitmap.Canvas do | |
if VideoChCount > 1 then | |
begin | |
Brush.Color := clBlack; | |
FillRect(Rect(0,0,frameBitmap.Width - 1, frameBitmap.Height - 1)); | |
Pen.Width := 1; | |
if colorScheme = CS_GRAYSCALE then Pen.Color := clOlive else Pen.Color := clRed; | |
Pen.Style := psSolid; | |
Pen.Mode := pmCopy; | |
for i := 1 to VideoChCount - 1 do | |
begin | |
MoveTo(i * (FrameWidth + 1) - 1, 0); | |
LineTo(i * (FrameWidth + 1) - 1, FrameHeight - 1); | |
end; | |
end; | |
with mpFile do | |
for m := 0 to MAX_CH - 1 do | |
if VideoChEnabled[m] then | |
begin | |
maxPixValue := ChMaxPixelValues[m]; | |
pixelXOffset := bitmapChRect[m].Left; | |
for i := 0 to FrameHeight - 1 do | |
begin | |
pLine := frameBitmap.ScanLine[i]; | |
for j := 0 to FrameWidth - 1 do | |
begin | |
k := j + i * FrameWidth; {index in frame data buffer for Ch1} | |
l := j + pixelXOffset; | |
pixelValue := Frames[CurrentFrameIndex].Channels[m].data[k]; | |
{Maps pixel value to 0..MAX_FALSE_COLORS - 1} | |
pixelValue := Muldiv(pixelValue, MAX_FALSE_COLORS - 1, MaxPixValue); | |
if pixelValue < 0 then pixelValue := 0; | |
if pixelValue > MAX_FALSE_COLORS - 1 then pixelValue := MAX_FALSE_COLORS - 1; | |
if colorScheme = CS_FALSECOLORS then | |
pLine^[l] := Mainform.falseColorTable[pixelValue] | |
else if colorScheme = CS_GRAYSCALE then | |
pLine^[l] := Mainform.grayScaleTable[pixelValue] | |
else | |
pLine^[l] := CustomColors[m][pixelValue]; | |
{Overlay Ch1 on Ch2} | |
if OverlayCh1onCh21.Checked and (m = 1) and (VideoChEnabled[0]) then | |
begin | |
pixel1 := pLine^[l]; | |
pixel0 := pLine^[l - pixelXOffset]; | |
pixel1.rgbtBlue := pixel1.rgbtBlue or pixel0.rgbtBlue; | |
pixel1.rgbtGreen := pixel1.rgbtGreen or pixel0.rgbtGreen; | |
pixel1.rgbtRed := pixel1.rgbtRed or pixel0.rgbtRed; | |
pLine^[l] := pixel1; | |
end; | |
{Overlay Ch2 on Ch3} | |
if OverlayCh2onCh31.Checked and (m = 2) and (VideoChEnabled[1]) then | |
begin | |
pixel1 := pLine^[l]; | |
pixel0 := pLine^[l - pixelXOffset]; | |
pixel1.rgbtBlue := pixel1.rgbtBlue or pixel0.rgbtBlue; | |
pixel1.rgbtGreen := pixel1.rgbtGreen or pixel0.rgbtGreen; | |
pixel1.rgbtRed := pixel1.rgbtRed or pixel0.rgbtRed; | |
pLine^[l] := pixel1; | |
end; | |
end; {for j} | |
end; {for i} | |
end; {end VideoChEnabled[m]} | |
if not HideROIs1.Checked then | |
if ROIList.Count > 0 then | |
for i := 0 to ROIList.Count - 1 do | |
with ROIList.ROIs[i] do | |
Draw(frameBitmap, bitmapChRect[Channel].Left); | |
Canvas.CopyRect(Rect(chRect[0].Left, chRect[0].Top, chRect[MAX_CH-1].Right, chRect[MAX_CH - 1].Bottom), | |
frameBitmap.Canvas, Rect(0, 0, frameBitmap.Width - 1, frameBitmap.Height - 1)); | |
end; | |
type | |
TVT8Array = array[0..Maxint div 16] of double; | |
TpVT8Array = ^TVT8Array; | |
procedure TViewerFrm.ExportToMatlab(chIndex, fromFrame, toFrame: integer; | |
frameName: string; startingIndex: integer; workspace: string); | |
var i, j, k, l: integer; | |
fullFrameName: string; | |
pArray: TpVT8Array; | |
frameArray, imaginaryArray: Variant; | |
begin | |
try | |
Screen.Cursor := crHourGlass; | |
if VarIsEmpty(Mainform.matlab) then MainForm.Options1Click(nil); | |
if not VarIsEmpty(Mainform.matlab) then | |
begin | |
frameArray := VarArrayCreate([0, mpFile.FrameHeight - 1, 0, mpFile.FrameWidth - 1], | |
varDouble); | |
imaginaryArray := Unassigned; | |
TVarData(imaginaryArray).VType := varDouble or varArray; | |
TVarData(imaginaryArray).VArray := nil; | |
for i := fromFrame to toFrame do | |
begin | |
if fromFrame = toFrame then | |
fullFrameName := frameName | |
else | |
fullFrameName := frameName + '_' + IntToStr(startingIndex + i - fromFrame); | |
pArray := VarArrayLock(frameArray); | |
for j := 0 to mpFile.FrameHeight - 1 do | |
for k := 0 to mpFile.FrameWidth - 1 do | |
begin | |
l := k + j * mpFile.FrameWidth; | |
pArray^[l] := mpFile.Frames[i].Channels[chIndex].data[l]; | |
end; | |
VarArrayUnlock(frameArray); | |
Mainform.matlab.PutFullMatrix(fullFrameName, workspace, | |
VarArrayRef(frameArray), VarArrayRef(imaginaryArray)); | |
end; | |
end; | |
finally | |
Screen.Cursor := crDefault; | |
end; | |
end; | |
procedure TViewerFrm.GetChRect; | |
var l, r, t, b, zl,zr, zt, zb, curCh, i: integer; | |
begin | |
with mpFile do | |
begin | |
l := 0; | |
r := 0; | |
t := 0; | |
b := FrameHeight - 1; | |
zl := 0; | |
zr := zl; | |
zt := Panel1.Height + 1; | |
zb := zt + fzoomIndex * FrameHeight - 1; | |
curCh := 0; | |
for i := 0 to MAX_CH - 1 do | |
begin | |
if VideoChEnabled[i] then | |
begin | |
{Let's have a border of 1 pixel * zoom if there more than two channels} | |
if (curCh > 0) then | |
begin | |
l := r + 2 {border}; | |
zl := zr + 1 + fzoomIndex; | |
end; | |
r := l + FrameWidth - 1; | |
zr := zl + fzoomIndex * FrameWidth - 1; | |
curCh := curCh + 1; | |
end; | |
bitmapChRect[i] := Rect(l, t, r, b); | |
chRect[i] := Rect(zl, zt, zr, zb); | |
end; | |
end; | |
end; | |
procedure TViewerFrm.MakeColorScale; | |
var firstX, lastX, firstY, lastY, i, j, validCh, | |
beginstripe, endstripe: integer; | |
curColor: TColor; | |
rgbTriple: TRGBTriple; | |
begin | |
with PaintBox1, PaintBox1.Canvas do | |
begin | |
Brush.Color := clBlack; | |
FillRect(ClientRect); | |
firstX := ClientRect.Left + 2; | |
lastX := ClientRect.Right - 2; | |
firstY := ClientRect.Top + 2; | |
lastY := ClientRect.Bottom - 2; | |
if GrayScale1.Checked then | |
for i := firstY to LastY do | |
begin | |
curColor := Muldiv(255, i - LastY, firstY - LastY); | |
if i = firstY then Pen.Color := RGB(255, 0, 0) else | |
if i = (lastY - firstY) div 2 + firstY then Pen.Color := RGB(0, 0, 255) else | |
Pen.Color := RGB(curColor, curColor, curColor); | |
MoveTo(firstX, i); | |
LineTo(lastX, i); | |
end | |
else if FalseColors1.Checked then | |
for i := firstY to LastY do | |
begin | |
rgbTriple := Mainform.falseColorTable[Muldiv(MAX_FALSE_COLORS -1, i - LastY, firstY - LastY)]; | |
Pen.Color := RGB(rgbTriple.rgbtRed, rgbTriple.rgbtGreen, rgbTriple.rgbtBlue); | |
MoveTo(firstX, i); | |
LineTo(lastX, i); | |
end | |
else {custom LUT} | |
with mpFile do | |
begin | |
validCh := 0; | |
for j := 0 to MAX_CH - 1 do | |
if VideoChEnabled[j] then | |
begin | |
beginstripe := firstX + Muldiv(validCh, lastX - firstX, VideoChCount); | |
endstripe := firstX + Muldiv(validCh + 1, lastX - firstX, VideoChCount); | |
for i := firstY to LastY do | |
begin | |
rgbTriple := CustomColors[j, | |
Muldiv(MAX_FALSE_COLORS - 1, i - LastY, firstY - LastY)]; | |
Pen.Color := RGB(rgbTriple.rgbtRed, rgbTriple.rgbtGreen, rgbTriple.rgbtBlue); | |
MoveTo(beginstripe, i); | |
LineTo(endstripe, i); | |
end; | |
validCh := validCh + 1; | |
end; | |
end; | |
end; {with begin} | |
end; | |
procedure TViewerFrm.OnNewFrame; | |
begin | |
AdjustWindowSize; | |
if AutomaticBackgroundCorrection1.Checked then mpFile.DoBackgroundCorrection; | |
DrawFrame; | |
StatusBar1.Panels[0].Text := 'Frame ' + IntToStr(CurrentFrameIndex + 1) + '/' | |
+ IntToStr(mpFile.FrameCount); | |
StatusBar1.Panels[6].Text := mpFile.FrameComment[CurrentFrameIndex]; | |
end; | |
procedure TViewerFrm.SelectROIPlot(bAllROIs: boolean; roiIndex: integer); | |
var i, fromFrame, toFrame: integer; | |
begin | |
if ROIList.Count > 0 then | |
begin | |
with PlotROIDlg do | |
begin | |
ComboBox1.Clear; | |
for i := 0 to ROIList.Count - 1 do | |
ComboBox1.Items.Add(IntToStr(i + 1)); | |
if bAllROIs then | |
begin | |
ComboBox1.Enabled := True; | |
ComboBox1.ItemIndex := 0; | |
end | |
else | |
begin | |
ComboBox1.ItemIndex := roiIndex; | |
ComboBox1.Enabled := False; | |
end; | |
SpinEdit1.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := 1; | |
SpinEdit2.MinValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit2.Value := mpFile.FrameCount; | |
if PlotROIDlg.ShowModal = mrOK then | |
begin | |
fromFrame := SpinEdit1.Value - 1; | |
toFrame := SpinEdit2.Value - 1; | |
if (fromFrame >= 0) and (fromFrame < mpFile.FrameCount) and | |
(toFrame >= 0) and (toFrame < mpFile.FrameCount) and | |
(toFrame >= fromFrame) then | |
begin | |
if (fromFrame <> toFrame) then | |
PlotROI(ComboBox1.ItemIndex, fromFrame, toFrame) | |
else | |
MessageDlg('Average ROI value = ' + | |
IntToStr(mpFile.GetROIAverageValue(ROIList, ComboBox1.ItemIndex, toFrame)), | |
mtInformation, [mbOK], 0); | |
end | |
else | |
MessageDlg('Invalid parameters', mtError, [mbOK], 0); | |
end; | |
end; | |
end; | |
end; | |
procedure TViewerFrm.PlotROI(roiIndex, fromFrame, toFrame: integer); | |
var aROIFrm: TROIFrm; | |
i: integer; | |
begin | |
try | |
Screen.Cursor := crHourGlass; | |
aROIFrm := TROIFrm.Create(Mainform); | |
aROIFrm.FrameRate := mpFile.FrameRate; | |
aROIFrm.FromFrame := fromFrame; | |
aROIFrm.ToFrame := toFrame; | |
aROIFrm.dataSize := toFrame - fromFrame + 1; | |
aROIFrm.Caption := Caption + '- ROI: ' + IntToStr(roiIndex + 1); | |
for i := fromFrame to toFrame do | |
aROIFrm.dataBuffer[i - fromFrame] := mpFile.GetROIAverageValue(ROIList, roiIndex, i); | |
aROIFrm.Show; | |
aROIFrm.FormResize(nil); {forces repainting} | |
finally | |
Screen.Cursor := crDefault; | |
end; | |
end; | |
procedure TViewerFrm.PlotLineProfile(chIndex: integer; rc: TRect); | |
var aROIFrm: TROIFrm; | |
i, j, x, y: integer; | |
bPlotX: boolean; | |
firstPt, lastPt: integer; | |
begin | |
bPlotX := (Abs(rc.Right - rc.Left) >= Abs(rc.Bottom - rc.Top)); | |
if (bPlotX and (rc.Left > rc.Right)) or (not bPlotX and (rc.Top > rc.Bottom)) then | |
begin | |
i := rc.Top; | |
rc.Top := rc.Bottom; | |
rc.Bottom := i; | |
i := rc.Left; | |
rc.Left := rc.Right; | |
rc.Right := i; | |
end; | |
if (Abs(rc.Right - rc.Left) < 10) and (Abs(rc.Bottom - rc.Top) < 10) then | |
MessageDlg('Too few points for a profile', mtError, [mbOK], 0) | |
else | |
begin | |
if bPlotX then | |
begin | |
firstPt := rc.Left; | |
lastPt := rc.Right; | |
end | |
else | |
begin | |
firstPt := rc.Top; | |
lastPt := rc.Bottom; | |
end; | |
aROIFrm := TROIFrm.Create(Mainform); | |
aROIFrm.bLineProfile := True; {turns off automatic X- axis caption} | |
aROIFrm.FromFrame := firstPt; | |
aROIFrm.ToFrame := lastPt; | |
aROIFrm.dataSize := lastPt - firstPt + 1; | |
aROIFrm.Caption := Caption + '- Line Profile: ' + | |
'(' + IntToStr(rc.Left) + ', ' + IntToStr(rc.Top) + ') to (' + | |
IntToStr(rc.Right) +', ' + IntToStr(rc.Bottom) + ')'; | |
for i := firstPt to lastPt do | |
begin | |
if bPlotX then | |
begin | |
x := i; | |
y := rc.Top + Muldiv(i - firstPt, rc.Bottom - rc.Top, lastPt - firstPt); | |
end | |
else | |
begin | |
y := i; | |
x := rc.Left + Muldiv(i - firstPt, rc.Right - rc.Left, lastPt - firstPt); | |
end; | |
j := x + y * mpFile.FrameWidth; | |
aROIFrm.dataBuffer[i - firstPt] := | |
mpFile.Frames[CurrentFrameIndex].Channels[chIndex].data[j]; | |
end; | |
aROIFrm.Show; | |
aROIFrm.FormResize(nil); {forces repainting} | |
end; | |
end; | |
procedure TViewerFrm.SetCurrentFrameIndex(newIndex: integer); | |
begin | |
if (newIndex < 0) or (newIndex >= mpFile.FrameCount) then Exit; | |
fCurrentFrameIndex := newIndex; | |
mpFile.ActiveFrameIndex := fCurrentFrameIndex; | |
OnNewFrame; | |
end; | |
procedure TViewerFrm.SetLUTColors; | |
var i, j, rval, gval, bval: integer; | |
begin | |
with mpFile do | |
for j := 0 to MAX_CH - 1 do | |
begin | |
if baseColors[j, 0] then rval := 255 else rval := 0; | |
if baseColors[j, 1] then gval := 255 else gval := 0; | |
if baseColors[j, 2] then bval := 255 else bval := 0; | |
for i := 0 to MaxPixels[j] - 1 do | |
begin | |
CustomColors[j, i].rgbtBlue := Muldiv(bval, i, MaxPixels[j] - 1); | |
CustomColors[j, i].rgbtGreen := Muldiv(gval, i, MaxPixels[j] - 1); | |
CustomColors[j, i].rgbtRed := Muldiv(rval, i, MaxPixels[j] - 1); | |
end; | |
CustomColors[j, 1023] := midRangeColors[j]; | |
for i := MaxPixels[j] to MAX_FALSE_COLORS - 1 do | |
CustomColors[j, i] := maxColors[j]; | |
end; | |
end; | |
function TViewerFrm.WindowToChannel(X, Y: integer; var retChannel: integer): boolean; | |
begin | |
Result := True; | |
with mpFile do | |
if PointStrictlyInRect(Point(X, Y), ChRect[0]) and VideoChEnabled[0] then | |
retChannel := 0 | |
else if PointStrictlyInRect(Point(X, Y), ChRect[1]) and VideoChEnabled[1] then | |
retChannel := 1 | |
else if PointStrictlyInRect(Point(X, Y), ChRect[2]) and VideoChEnabled[2] then | |
retChannel := 2 | |
else if PointStrictlyInRect(Point(X, Y), ChRect[3]) and VideoChEnabled[3] then | |
retChannel := 3 | |
else | |
Result := False; | |
end; | |
function TViewerFrm.WindowToFrameX(chIndex, xVal: integer): integer; | |
begin | |
Result := (xVal - chRect[chIndex].Left) div fZoomIndex; | |
end; | |
function TViewerFrm.WindowToFrameY(yVal: integer): integer; | |
begin | |
Result := (yVal - chRect[0].Top) div fZoomIndex; | |
end; | |
{--------------------------------- PUBLIC -------------------------------------} | |
procedure TViewerFrm.Initialize(thempFile: TMPFile; viewerIndex: integer); | |
begin | |
mpFile := thempFile; | |
SetLUTColors; | |
frameBitmap.Width := mpFile.VideoChCount * mpFile.FrameWidth + mpFile.VideoChCount - 1; | |
frameBitmap.Height := mpFile.FrameHeight; | |
fZoomIndex := 1; | |
fCurrentFrameIndex := 0; | |
Caption := ExtractFileName(mpFile.Filename) + ' <- Viewer ' + IntToStr(viewerIndex); | |
AdjustWindowSize; | |
with mpfile do | |
OverlayCh2onCh31.Enabled := | |
ChEnabled[1] and ChEnabled[2] and VideoChEnabled[2]; | |
end; | |
{-------------------- CONSTRUCTION - DESTRUCTION ------------------------------} | |
procedure TViewerFrm.FormCreate(Sender: TObject); | |
begin | |
frameBitmap := TBitmap.Create; | |
frameBitmap.HandleType := bmDIB; | |
frameBitmap.PixelFormat := pf24bit; | |
ROIList := TROIList.Create; | |
PrevFrame1.ShortCut := ShortCut(VK_LEFT, []); | |
NextFrame1.ShortCut := ShortCut(VK_RIGHT, []); | |
end; | |
procedure TViewerFrm.FormActivate(Sender: TObject); | |
begin | |
with Mainform do | |
begin | |
NewFile1.Enabled := True; | |
OpenFile1.Enabled := True; | |
if mpFile <> nil then | |
FileAs1.Enabled := mpFile.IsMemoryFile | |
else | |
FileAs1.Enabled := False; | |
FileInformation1.Enabled := True; | |
Close1.Enabled := True; | |
end; | |
end; | |
procedure TViewerFrm.FormDeactivate(Sender: TObject); | |
begin | |
with Mainform do | |
begin | |
NewFile1.Enabled := False; | |
OpenFile1.Enabled := False; | |
FileAs1.Enabled := False; | |
FileInformation1.Enabled := False; | |
Close1.Enabled := False; | |
end; | |
end; | |
procedure TViewerFrm.FormClose(Sender: TObject; var Action: TCloseAction); | |
begin | |
action := caFree; | |
FreeAndNil(frameBitmap); | |
if (mpFile <> nil) and (not Mainform.bAppClosing) then mpFile.OnWndClose(self); | |
mpFile := nil; | |
end; | |
procedure TViewerFrm.FormDestroy(Sender: TObject); | |
begin | |
{ frameBitmap.Free;} | |
ROIList.Free; | |
end; | |
{---------------------------------- EVENTS ------------------------------------} | |
procedure TViewerFrm.ToolButton2Click(Sender: TObject); | |
begin | |
CurrentFrameIndex := CurrentFrameIndex - 1; | |
end; | |
procedure TViewerFrm.ToolButton4Click(Sender: TObject); | |
begin | |
CurrentFrameIndex := CurrentFrameIndex + 1; | |
end; | |
procedure TViewerFrm.ToolButton3Click(Sender: TObject); | |
begin | |
ToolButton1.Down := False; | |
ToolButton5.Down := False; | |
end; | |
procedure TViewerFrm.ToolButton1Click(Sender: TObject); | |
begin | |
while (CurrentFrameIndex > 0) and (ToolButton1.Down) do | |
begin | |
CurrentFrameIndex := CurrentFrameIndex - 1; | |
Application.ProcessMessages; | |
end; | |
ToolButton1.Down := False; | |
end; | |
procedure TViewerFrm.ToolButton5Click(Sender: TObject); | |
begin | |
while (CurrentFrameIndex < mpFile.FrameCount - 1) and (ToolButton5.Down) do | |
begin | |
CurrentFrameIndex := CurrentFrameIndex + 1; | |
Application.ProcessMessages; | |
end; | |
ToolButton5.Down := False; | |
end; | |
procedure TViewerFrm.FirstFrame1Click(Sender: TObject); | |
begin | |
CurrentFrameIndex := 0; | |
end; | |
procedure TViewerFrm.LastFrame1Click(Sender: TObject); | |
begin | |
CurrentFrameIndex := mpFile.FrameCount - 1; | |
end; | |
procedure TViewerFrm.GotoFrame1Click(Sender: TObject); | |
var sFrameIndex: string; | |
iFrameIndex: integer; | |
begin | |
if (mpFile = nil) or (mpFile.FrameCount = 0) then Exit; | |
sFrameIndex := '1'; | |
if InputQuery('Go to Frame', 'Enter Frame Index', sFrameIndex) then | |
begin | |
iFrameIndex := StrToInt(sFrameIndex); | |
if (iFrameIndex < 1) or (iFrameIndex > mpFile.FrameCount) then | |
MessageDlg('Invalid Frame Index.', mtError, [mbOK], 0) | |
else | |
CurrentFrameIndex := iFrameIndex - 1; | |
end; | |
end; | |
procedure TViewerFrm.Comments1Click(Sender: TObject); | |
var sFrameComment: string; | |
begin | |
if (mpFile = nil) or (mpFile.FrameCount = 0) then Exit; | |
sFrameComment := mpFile.FrameComment[CurrentFrameIndex]; | |
if InputQuery('Frame Comment', 'Enter Frame Comment', sFrameComment) then | |
begin | |
mpFile.FrameComment[CurrentFrameIndex] := sFrameComment; | |
StatusBar1.Panels[6].Text := sFrameComment; | |
end; | |
end; | |
procedure TViewerFrm.Grayscale1Click(Sender: TObject); | |
begin | |
if Grayscale1.Checked then Exit; | |
Grayscale1.Checked := True; | |
colorScheme := CS_GRAYSCALE; | |
FalseColors1.Checked := False; | |
CustomColors1.Checked := False; | |
MakeColorScale; | |
DrawFrame; | |
end; | |
procedure TViewerFrm.Increasezoom1Click(Sender: TObject); | |
begin | |
if fZoomIndex < 5 then | |
begin | |
fZoomIndex := fZoomIndex + 1; | |
AdjustWindowSize; | |
DrawFrame; | |
end; | |
end; | |
procedure TViewerFrm.DecreaseZoom1Click(Sender: TObject); | |
begin | |
if fZoomIndex > 1 then | |
begin | |
fZoomIndex := fZoomIndex - 1; | |
AdjustWindowSize; | |
DrawFrame; | |
end; | |
end; | |
procedure TViewerFrm.NewFrameViewer1Click(Sender: TObject); | |
begin | |
mpFile.NewViewer; | |
end; | |
procedure TViewerFrm.SaveFrameasBitmap1Click(Sender: TObject); | |
begin | |
if CheckNoFrame then Exit; | |
with SaveDialog1 do | |
begin | |
DefaultExt := 'BMP'; | |
Filter := 'Bitmaps (*.BMP)|*.BMP|All Files (*.*)|*.*'; | |
InitialDir := ExtractFilePath(mpFile.Filename); | |
Title := 'Save Frame as Bitmap'; | |
if Execute then frameBitmap.SaveToFile(Filename); | |
end; | |
end; | |
procedure TViewerFrm.FormPaint(Sender: TObject); | |
begin | |
if frameBitmap = nil then Exit; | |
with Canvas do | |
begin | |
Brush.Color := clOlive; | |
FillRect(ClientRect); | |
end; | |
Canvas.CopyRect(Rect(chRect[0].Left, chRect[0].Top, chRect[MAX_CH - 1].Right, chRect[MAX_CH - 1].Bottom), | |
frameBitmap.Canvas, Rect(0, 0, frameBitmap.Width - 1, frameBitmap.Height - 1)); | |
end; | |
procedure TViewerFrm.Gammacorrection1Click(Sender: TObject); | |
var blackLevel, whiteLevel, i, chIndex: integer; | |
begin | |
if CheckNoFrame then Exit; | |
mpFile.ActiveFrameIndex := CurrentFrameIndex; | |
GammaFrm.bInitializing := True; | |
GammaFrm.mpFile := mpFile; | |
GammaFrm.InitGUI(mpFile); | |
GammaFrm.CheckBox1.Checked := False; | |
GammaFrm.CheckBox1.Enabled := mpFile.IsMemoryFile; | |
GammaFrm.TrackBar1.Position := 128; {default black level = 0} | |
GammaFrm.TrackBar2.Position := 2047 + 128; {default black level = 0} | |
GammaFrm.Label1.Caption := 'Black Level = 0'; | |
GammaFrm.Label2.Caption := 'White Level = 2047'; | |
GammaFrm.bInitializing := False; | |
if GammaFrm.ShowModal = mrOK then | |
begin | |
blackLevel := GammaFrm.TrackBar1.Position - 128; | |
whiteLevel := GammaFrm.TrackBar2.Position - 128; | |
if blackLevel >= whiteLevel then | |
MessageDlg('Black Level must be smaller than White Level.', mtError, | |
[mbOK], 0) | |
else | |
begin | |
chIndex := GammaFrm.SelectedCh; | |
if whiteLevel > mpFile.ChMaxPixelValues[chIndex] then | |
begin | |
MessageDlg('Adjusted White Level to maximal possible pixel value.', | |
mtWarning, [mbOK], 0); | |
whiteLevel := mpFile.ChMaxPixelValues[chIndex]; | |
end; | |
if GammaFrm.CheckBox1.Checked then | |
for i := 0 to mpFile.FrameCount - 1 do | |
(mpFile.Frames[i].channels[chIndex] as TVideoFrame). | |
GammaCorrection(blackLevel, whiteLevel) | |
else | |
(mpFile.Frames[CurrentFrameIndex].channels[chIndex] as TVideoFrame). | |
GammaCorrection(blackLevel, whiteLevel); | |
OnNewFrame; | |
end; | |
end; | |
end; | |
procedure TViewerFrm.AverageFrames1Click(Sender: TObject); | |
var fromFrame, toFrame, repeatCount, lastFrame, chIndex, i: integer; | |
oldCursor: TCursor; | |
destMPFile: TMPFile; | |
begin | |
if CheckNoFrame then Exit; | |
if Mainform.fileList.WorkspaceCount = 0 then | |
MessageDlg('No workspace for this operation.' + CRLF + | |
'Create a workspace file first.', mtInformation, [mbOK], 0) | |
else | |
begin | |
with opframedlg do | |
begin | |
Caption := 'Average Frames'; | |
opframedlg.InitGUI(mpFile); | |
Mainform.fileList. | |
FillComboBoxWithWorkspaces(ComboBox1); | |
ComboBox1.ItemIndex := 0; | |
Label1.Caption := 'From Frame'; | |
Label3.Caption := 'To Frame'; | |
SpinEdit1.MinValue := 1; | |
SpinEdit2.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := CurrentFrameIndex + 1; | |
SpinEdit2.Value := CurrentFrameIndex + 1; | |
Label4.Visible := True; | |
Label4.Caption := 'Repeat'; | |
SpinEdit3.MinValue := 1; | |
SpinEdit3.MaxValue := mpFile.FrameCount; | |
SpinEdit3.Value := 1; | |
SpinEdit3.Visible := True; | |
Label5.Visible := False; | |
SpinEdit4.Visible := False; | |
end; | |
if opframedlg.ShowModal = mrOK then | |
begin | |
fromFrame := opframedlg.SpinEdit1.Value - 1; | |
toFrame := opframedlg.SpinEdit2.Value - 1; | |
repeatCount := opframedlg.SpinEdit3.Value; | |
chIndex := opframedlg.SelectedCh; | |
if (fromFrame <= toFrame) and (fromFrame >= 0) and (fromFrame | |
< mpFile.FrameCount) and (toFrame >= 0) and (toFrame < | |
mpFile.FrameCount) then | |
begin | |
lastFrame := fromFrame + (toFrame - fromFrame + 1) * repeatCount | |
- 1; | |
if lastFrame >= mpFile.FrameCount then | |
MessageDlg('Too many repeats.', mtError, [mbOK], 0) else | |
begin | |
destMPFile := TMPFile(opframedlg.ComboBox1.Items. | |
Objects[opframedlg.ComboBox1.ItemIndex]); | |
if destMPFile.SizeOfFrameCompatible(mpFile.FrameWidth, mpFile.FrameHeight) then | |
begin | |
oldCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
for i := 0 to repeatCount - 1 do | |
mpFile.AverageFrames(chIndex, | |
fromFrame + i * (toFrame- fromFrame + 1), | |
toFrame + i * (toFrame- fromFrame + 1), | |
destMPFile); | |
destMPFile.OnNewFrames; | |
finally | |
Screen.Cursor := oldCursor; | |
end; | |
end; | |
end; | |
end | |
else | |
MessageDlg('Invalid Average Frames parameters', mtError, | |
[mbOK], 0); | |
end; | |
end; | |
end; | |
procedure TViewerFrm.CopyFrames2Click(Sender: TObject); | |
var fromFrame, toFrame, chIndex: integer; | |
oldCursor: TCursor; | |
destMPFile: TMPFile; | |
begin | |
if CheckNoFrame then Exit; | |
if Mainform.fileList.WorkspaceCount = 0 then | |
MessageDlg('No workspace for this operation.' + CRLF + | |
'Create a workspace file first.', mtInformation, [mbOK], 0) | |
else | |
begin | |
with opframedlg do | |
begin | |
Caption := 'Copy Frames'; | |
opframedlg.InitGUI(mpFile); | |
Mainform.fileList. | |
FillComboBoxWithWorkspaces(ComboBox1); | |
ComboBox1.ItemIndex := 0; | |
Label1.Caption := 'From Frame'; | |
Label3.Caption := 'To Frame'; | |
SpinEdit1.MinValue := 1; | |
SpinEdit2.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := CurrentFrameIndex + 1; | |
SpinEdit2.Value := CurrentFrameIndex + 1; | |
Label4.Visible := False; | |
SpinEdit3.Visible := False; | |
Label5.Visible := False; | |
SpinEdit4.Visible := False; | |
end; | |
if opframedlg.ShowModal = mrOK then | |
begin | |
fromFrame := opframedlg.SpinEdit1.Value - 1; | |
toFrame := opframedlg.SpinEdit2.Value - 1; | |
chIndex := opframedlg.SelectedCh; | |
if (fromFrame <= toFrame) and (fromFrame >= 0) and (fromFrame | |
< mpFile.FrameCount) and (toFrame >= 0) and (toFrame < | |
mpFile.FrameCount) then | |
begin | |
destMPFile := TMPFile(opframedlg.ComboBox1.Items. | |
Objects[opframedlg.ComboBox1.ItemIndex]); | |
if destMPFile.SizeOfFrameCompatible(mpFile.FrameWidth, mpFile.FrameHeight) then | |
begin | |
oldCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
mpFile.CopyFrames(chIndex, fromFrame, toFrame, | |
destMPFile); | |
destMPFile.OnNewFrames; | |
finally | |
Screen.Cursor := oldCursor; | |
end; | |
end; | |
end | |
else | |
MessageDlg('Invalid Copy Frames parameters', mtError, | |
[mbOK], 0); | |
end; | |
end; | |
end; | |
{Z axis projection} | |
procedure TViewerFrm.CreateProjection1Click(Sender: TObject); | |
var fromFrame, toFrame, chIndex: integer; | |
oldCursor: TCursor; | |
destMPFile: TMPFile; | |
begin | |
if CheckNoFrame then Exit; | |
if Mainform.fileList.WorkspaceCount = 0 then | |
MessageDlg('No workspace for this operation.' + CRLF + | |
'Create a workspace file first.', mtInformation, [mbOK], 0) | |
else | |
begin | |
with opframedlg do | |
begin | |
Caption := 'Project Frames on Z axis'; | |
opframedlg.InitGUI(mpFile); | |
Mainform. | |
fileList.FillComboBoxWithWorkspaces(ComboBox1); | |
ComboBox1.ItemIndex := 0; | |
Label1.Caption := 'From Frame'; | |
Label3.Caption := 'To Frame'; | |
SpinEdit1.MinValue := 1; | |
SpinEdit2.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := CurrentFrameIndex + 1; | |
SpinEdit2.Value := CurrentFrameIndex + 1; | |
Label4.Visible := False; | |
SpinEdit3.Visible := False; | |
Label5.Visible := False; | |
SpinEdit4.Visible := False; | |
end; | |
if opframedlg.ShowModal = mrOK then | |
begin | |
fromFrame := opframedlg.SpinEdit1.Value - 1; | |
toFrame := opframedlg.SpinEdit2.Value - 1; | |
chIndex := opframedlg.SelectedCh; | |
if (fromFrame <= toFrame) and (fromFrame >= 0) and (fromFrame | |
< mpFile.FrameCount) and (toFrame >= 0) and (toFrame < | |
mpFile.FrameCount) then | |
begin | |
destMPFile := TMPFile(opframedlg.ComboBox1.Items. | |
Objects[opframedlg.ComboBox1.ItemIndex]); | |
if destMPFile.SizeOfFrameCompatible(mpFile.FrameWidth, mpFile.FrameHeight) then | |
begin | |
oldCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
mpFile.StackZ(chIndex, fromFrame, toFrame, | |
destMPFile); | |
finally | |
Screen.Cursor := oldCursor; | |
end; | |
end; | |
end | |
else | |
MessageDlg('Invalid Projection Frames parameters', mtError, | |
[mbOK], 0); | |
end; | |
end; | |
end; | |
procedure TViewerFrm.ProjectFrameonYaxis1Click(Sender: TObject); | |
var fromFrame, toFrame, chIndex, fromX, toX: integer; | |
oldCursor: TCursor; | |
destMPFile: TMPFile; | |
begin | |
if CheckNoFrame then Exit; | |
if Mainform.fileList.WorkspaceCount = 0 then | |
MessageDlg('No workspace for this operation.' + CRLF + | |
'Create a workspace file first.', mtInformation, [mbOK], 0) | |
else | |
begin | |
with opframedlg do | |
begin | |
Caption := 'Project Frames on Y axis'; | |
opframedlg.InitGUI(mpFile); | |
Mainform.fileList. | |
FillComboBoxWithWorkspaces(ComboBox1); | |
ComboBox1.ItemIndex := 0; | |
Label1.Caption := 'From Frame'; | |
Label3.Caption := 'To Frame'; | |
SpinEdit1.MinValue := 1; | |
SpinEdit2.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := CurrentFrameIndex + 1; | |
SpinEdit2.Value := CurrentFrameIndex + 1; | |
Label4.Visible := True; | |
Label4.Caption := 'From X'; | |
SpinEdit3.MinValue := 0; | |
SpinEdit3.MaxValue := mpFile.FrameWidth - 1; | |
SpinEdit3.Value := 0; | |
SpinEdit3.Visible := True; | |
Label5.Visible := True; | |
Label5.Caption := 'To X'; | |
SpinEdit4.MinValue := 0; | |
SpinEdit4.MaxValue := mpFile.FrameWidth - 1; | |
SpinEdit4.Value := mpFile.FrameWidth - 1; | |
SpinEdit4.Visible := True; | |
end; | |
if opframedlg.ShowModal = mrOK then | |
begin | |
fromFrame := opframedlg.SpinEdit1.Value - 1; | |
toFrame := opframedlg.SpinEdit2.Value - 1; | |
chIndex := opframedlg.SelectedCh; | |
fromX := opframedlg.SpinEdit3.Value; | |
toX := opframedlg.SpinEdit4.Value; | |
if (fromFrame <= toFrame) and (fromFrame >= 0) and (fromFrame | |
< mpFile.FrameCount) and (toFrame >= 0) and (toFrame < | |
mpFile.FrameCount) and | |
(fromX >= 0) and (fromX < mpFile.FrameWidth) and | |
(toX >= 0) and (toX < mpFile.FrameWidth) and | |
(toX >= fromX) then | |
begin | |
destMPFile := TMPFile(opframedlg.ComboBox1.Items. | |
Objects[opframedlg.ComboBox1.ItemIndex]); | |
if destMPFile.SizeOfFrameCompatible(mpFile.FrameHeight, | |
toFrame - fromFrame + 1) then | |
begin | |
oldCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
mpFile.StackY(chIndex, fromFrame, toFrame, fromX, toX, | |
destMPFile); | |
finally | |
Screen.Cursor := oldCursor; | |
end; | |
end; | |
end | |
else | |
MessageDlg('Invalid Projection Frames parameters', mtError, | |
[mbOK], 0); | |
end; | |
end; | |
end; | |
procedure TViewerFrm.ProjectFramesonXaxis1Click(Sender: TObject); | |
var fromFrame, toFrame, chIndex, fromY, toY: integer; | |
oldCursor: TCursor; | |
destMPFile: TMPFile; | |
begin | |
if CheckNoFrame then Exit; | |
if Mainform.fileList.WorkspaceCount = 0 then | |
MessageDlg('No workspace for this operation.' + CRLF + | |
'Create a workspace file first.', mtInformation, [mbOK], 0) | |
else | |
begin | |
with opframedlg do | |
begin | |
Caption := 'Project Frames on X axis'; | |
opframedlg.InitGUI(mpFile); | |
Mainform.fileList. | |
FillComboBoxWithWorkspaces(ComboBox1); | |
ComboBox1.ItemIndex := 0; | |
Label1.Caption := 'From Frame'; | |
Label3.Caption := 'To Frame'; | |
SpinEdit1.MinValue := 1; | |
SpinEdit2.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := CurrentFrameIndex + 1; | |
SpinEdit2.Value := CurrentFrameIndex + 1; | |
Label4.Visible := True; | |
Label4.Caption := 'From Y'; | |
SpinEdit3.MinValue := 0; | |
SpinEdit3.MaxValue := mpFile.FrameHeight - 1; | |
SpinEdit3.Value := 0; | |
SpinEdit3.Visible := True; | |
Label5.Visible := True; | |
Label5.Caption := 'To Y'; | |
SpinEdit4.MinValue := 0; | |
SpinEdit4.MaxValue := mpFile.FrameHeight - 1; | |
SpinEdit4.Value := mpFile.FrameHeight - 1; | |
SpinEdit4.Visible := True; | |
end; | |
if opframedlg.ShowModal = mrOK then | |
begin | |
fromFrame := opframedlg.SpinEdit1.Value - 1; | |
toFrame := opframedlg.SpinEdit2.Value - 1; | |
chIndex := opframedlg.SelectedCh; | |
fromY := opframedlg.SpinEdit3.Value; | |
toY := opframedlg.SpinEdit4.Value; | |
if (fromFrame <= toFrame) and (fromFrame >= 0) and (fromFrame | |
< mpFile.FrameCount) and (toFrame >= 0) and (toFrame < | |
mpFile.FrameCount) and | |
(fromY >= 0) and (fromY < mpFile.FrameHeight) and | |
(toY >= 0) and (toY < mpFile.FrameHeight) and | |
(toY >= fromY) then | |
begin | |
destMPFile := TMPFile(opframedlg.ComboBox1.Items. | |
Objects[opframedlg.ComboBox1.ItemIndex]); | |
if destMPFile.SizeOfFrameCompatible(mpFile.FrameWidth, | |
toFrame - fromFrame + 1) then | |
begin | |
oldCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
mpFile.StackX(chIndex, fromFrame, toFrame, fromY, toY, | |
destMPFile); | |
finally | |
Screen.Cursor := oldCursor; | |
end; | |
end; | |
end | |
else | |
MessageDlg('Invalid Projection Frames parameters', mtError, | |
[mbOK], 0); | |
end; | |
end; | |
end; | |
procedure TViewerFrm.SubtractwithFrame1Click(Sender: TObject); | |
var plusFrame, minusFrame, repeatCount, lastFrame, chIndex, i: integer; | |
oldCursor: TCursor; | |
destMPFile: TMPFile; | |
begin | |
if CheckNoFrame then Exit; | |
if Mainform.fileList.WorkspaceCount = 0 then | |
MessageDlg('No workspace for this operation.' + CRLF + | |
'Create a workspace file first.', mtInformation, [mbOK], 0) | |
else | |
begin | |
opframedlg.Caption := 'Subtract Frames'; | |
opframedlg.InitGUI(mpFile); | |
Mainform.fileList.FillComboBoxWithWorkspaces(opframedlg.ComboBox1); | |
opframedlg.ComboBox1.ItemIndex := 0; | |
opframedlg.Label1.Caption := '+ Frame'; | |
opframedlg.Label3.Caption := '- Frame'; | |
opframedlg.Label4.Caption := 'Repeat'; | |
opframedlg.SpinEdit3.Enabled := True; | |
opframedlg.SpinEdit3.Value := 1; | |
opframedlg.SpinEdit1.MinValue := 1; | |
opframedlg.SpinEdit2.MinValue := 1; | |
opframedlg.SpinEdit1.MaxValue := mpFile.FrameCount; | |
opframedlg.SpinEdit2.MaxValue := mpFile.FrameCount; | |
opframedlg.SpinEdit1.Value := CurrentFrameIndex + 1; | |
opframedlg.SpinEdit2.Value := CurrentFrameIndex + 1; | |
if opframedlg.ShowModal = mrOK then | |
begin | |
plusFrame := opframedlg.SpinEdit1.Value - 1; | |
minusFrame := opframedlg.SpinEdit2.Value - 1; | |
repeatCount := opframedlg.SpinEdit3.Value; | |
chIndex := opframedlg.SelectedCh; | |
if (plusFrame >= 0) and (plusFrame < mpFile.FrameCount) and | |
(minusFrame >= 0) and (minusFrame < mpFile.FrameCount) then | |
begin | |
if plusFrame >= minusFrame then | |
lastFrame := plusFrame + repeatCount - 1 | |
else | |
lastFrame := minusFrame + repeatCount - 1; | |
if lastFrame >= mpFile.FrameCount then | |
MessageDlg('Too many repeats.', mtError, [mbOK], 0) else | |
begin | |
destMPFile := TMPFile(opframedlg.ComboBox1.Items. | |
Objects[opframedlg.ComboBox1.ItemIndex]); | |
if destMPFile.SizeOfFrameCompatible(mpFile.FrameWidth, | |
mpFile.FrameHeight) then | |
begin | |
oldCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
for i := 0 to repeatCount - 1 do | |
mpFile.SubtractFrame(chIndex, | |
plusFrame + i, | |
minusFrame + i, | |
destMPFile); | |
destMPFile.OnNewFrames; | |
finally | |
Screen.Cursor := oldCursor; | |
end; | |
end; | |
end; | |
end | |
else | |
MessageDlg('Invalid Subtract Frames parameters', mtError, | |
[mbOK], 0); | |
end; | |
end; | |
end; | |
procedure TViewerFrm.DeleteallROIs1Click(Sender: TObject); | |
begin | |
ROIList.Clear; | |
DrawFrame; | |
end; | |
procedure TViewerFrm.MakeAVIMovie1Click(Sender: TObject); | |
var chIndex, fromFrame, toFrame: integer; | |
oldCursor: TCursor; | |
aColorScheme: TColorScheme; | |
begin | |
if CheckNoFrame then Exit; | |
with AVIOptDlg do | |
begin | |
GroupBox2.Enabled := True; | |
RadioButton5.Checked := True; | |
Label2.Visible := True; | |
SpinEdit3.Visible := True; | |
Label4.Visible := True; | |
InitGUI(mpFile); | |
SpinEdit1.MinValue := 1; | |
SpinEdit2.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := 1; | |
SpinEdit2.Value := mpFile.FrameCount; | |
SpinEdit3.Value := Round(mpFile.FrameRate); | |
Caption := 'Create AVI Movie'; | |
end; | |
with SaveDialog1 do | |
begin | |
DefaultExt := 'AVI'; | |
Filter := 'Video Files (*.AVI)|*.AVI|All Files (*.*)|*.*'; | |
Title := 'Create AVI File'; | |
if Execute then | |
if AVIOptDlg.ShowModal = mrOK then | |
begin | |
chIndex := AVIOptDlg.SelectedCh; | |
fromFrame := AVIOptDlg.SpinEdit1.Value - 1; | |
toFrame := AVIOptDlg.SpinEdit2.Value - 1; | |
if (fromFrame >= 0) and (fromFrame < mpFile.FrameCount) and | |
(toFrame >= 0) and (toFrame < mpFile.FrameCount) and | |
(AVIOptDlg.SpinEdit3.Value > 0) then | |
begin | |
oldCursor := Screen.Cursor; | |
if AVIOptDlg.RadioButton5.Checked then | |
aColorScheme := CS_GRAYSCALE | |
else if AVIOptDlg.RadioButton6.Checked then | |
aColorScheme := CS_FALSECOLORS | |
else | |
aColorScheme := CS_CUSTOMLUT; | |
try | |
Screen.Cursor := crHourGlass; | |
mpFile.MakeAVIMovie(SaveDialog1.Filename, chIndex, | |
fromFrame, toFrame, AVIOptDlg.SpinEdit3.Value, aColorScheme, self, | |
OverlayCh1onCh21.Checked); | |
finally | |
Screen.Cursor := oldCursor; | |
end; | |
end | |
else | |
MessageDlg('Invalid frames', mtError, [mbOK], 0); | |
end; | |
end; | |
end; | |
procedure TViewerFrm.DeleteallObjects1Click(Sender: TObject); | |
begin | |
if mpFile = nil then Exit; | |
if ROIList.Count = 0 then Exit; | |
ROIList.Clear; | |
OnNewFrame; | |
HideROIs1.Checked := False; | |
PlotROIofObjects1.Enabled := False; | |
HideROIs1.Enabled := False; | |
DeleteallObjects1.Enabled := False; | |
end; | |
procedure TViewerFrm.HideROIs1Click(Sender: TObject); | |
begin | |
if mpFile = nil then Exit; | |
if ROIList.Count = 0 then Exit; | |
HideROIs1.Checked := not HideROIs1.Checked; | |
OnNewFrame; | |
end; | |
procedure TViewerFrm.CreateRectangularROI1Click(Sender: TObject); | |
begin | |
if CheckNoFrame then Exit; | |
CreateRectangularROI1.Checked := not CreateRectangularROI1.Checked; | |
ToolButton7.Down := CreateRectangularROI1.Checked; | |
if CreateRectangularROI1.Checked then | |
begin | |
ToolButton8.Down := False; | |
CreateEllipticalROI1.Checked := False; | |
end; | |
end; | |
procedure TViewerFrm.CreateEllipticalROI1Click(Sender: TObject); | |
begin | |
if CheckNoFrame then Exit; | |
CreateEllipticalROI1.Checked := not CreateEllipticalROI1.Checked; | |
ToolButton8.Down := CreateEllipticalROI1.Checked; | |
if CreateEllipticalROI1.Checked then | |
begin | |
ToolButton7.Down := False; | |
CreateRectangularROI1.Checked := False; | |
end; | |
end; | |
procedure TViewerFrm.FindObjects1Click(Sender: TObject); | |
var chIndex, oldROICount, fromFrame, toFrame, | |
threshold, minArea, | |
templateFrom, templateTo: integer; | |
begin | |
if CheckNoFrame then Exit; | |
with DetectROIDlg do | |
begin | |
CheckBox1.Checked := False; | |
CheckBox1.Enabled := (mpFile.VideoChCount >= 2); | |
SetGUI(mpFile); {sets radiobuttons in form} | |
Label2.Caption := 'Threshold (1..' + IntToStr(mpFile.MaxPixelValue) + ')'; | |
SpinEdit1.MinValue := 1; | |
SpinEdit2.MinValue := 1; | |
SpinEdit5.MinValue := 1; | |
SpinEdit6.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit3.MaxValue := mpFile.MaxPixelValue; | |
SpinEdit5.MaxValue := mpFile.FrameCount; | |
SpinEdit6.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := 1; | |
SpinEdit2.Value := mpFile.FrameCount; | |
SpinEdit5.Value := 1; | |
SpinEdit6.Value := 10; | |
end; | |
if DetectROIDlg.ShowModal = mrOK then | |
begin | |
chIndex := DetectROIDlg.SelectedCh; | |
fromFrame := DetectROIDlg.SpinEdit1.Value - 1; | |
toFrame := DetectROIDlg.SpinEdit2.Value - 1; | |
threshold := DetectROIDlg.SpinEdit3.Value; | |
minArea := DetectROIDlg.SpinEdit4.Value; | |
templateFrom := DetectROIDlg.SpinEdit5.Value; | |
templateTo := DetectROIDlg.SpinEdit6.Value; | |
if (fromFrame >= 0) and (fromFrame < mpFile.FrameCount) | |
and (toFrame >= 0 ) and (toFrame < mpFile.FrameCount) | |
and (threshold > 0) and (threshold <= 2047) | |
and (minArea > 0) and (minArea < mpFile.FrameWidth * mpFile.FrameHeight) | |
and (templateFrom >= 0 ) and (templateFrom < mpFile.FrameCount) | |
and (templateTo >= 0 ) and (templateTo < mpFile.FrameCount) | |
and (templateFrom <= templateTo ) then | |
begin | |
oldROICount := ROIList.Count; | |
try | |
Screen.Cursor := crHourGlass; | |
mpFile.DetectROIs(ROIList, chIndex, fromFrame, toFrame, threshold, minArea, templateFrom, templateTo); | |
Screen.Cursor := crDefault; | |
MessageDlg(IntToStr(ROIList.Count - oldROICount) + ' ROIs found.', | |
mtInformation, [mbOK], 0); | |
if ROIList.Count > oldROICount then | |
begin | |
HideROIs1.Enabled := True; | |
PlotROIofObjects1.Enabled := True; | |
DeleteallObjects1.Enabled := True; | |
if DetectROIDlg.CheckBox1.Checked then mpFile.CloneROIs(ROIList, oldROICount); | |
OnNewFrame; | |
end; | |
except | |
Screen.Cursor := crDefault; | |
end; | |
end | |
else | |
MessageDlg('Invalid parameter(s) to detect ROIs.', mtError, [mbOK], 0); | |
end; | |
end; | |
procedure TViewerFrm.PlotROIofObjects1Click(Sender: TObject); | |
begin | |
SelectROIPlot(True, 0); | |
end; | |
procedure TViewerFrm.FormMouseDown(Sender: TObject; Button: TMouseButton; | |
Shift: TShiftState; X, Y: Integer); | |
var origin: TPoint; | |
sc: TRect; | |
begin | |
if mpFile = nil then Exit; | |
if mpFile.FrameCount = 0 then Exit; | |
origin := ClientOrigin; | |
if CreateRectangularROI1.Checked or CreateLineProfile1.Checked or | |
AreaStats1.Checked or CreateEllipticalROI1.Checked then | |
begin | |
if WindowToChannel(X, Y, currentChannel) then | |
if mpFile.VideoChEnabled[currentChannel] then | |
begin | |
sc := chRect[currentChannel]; | |
OffsetRect(sc, origin.X, origin.Y); | |
ClipCursor(@sc); | |
if CreateRectangularROI1.Checked then | |
mouseAction := maRectangularROI | |
else if CreateEllipticalROI1.Checked then | |
mouseAction := maEllipticROI | |
else if CreateLineProfile1.Checked then | |
mouseAction := maLineProfile | |
else if AreaStats1.Checked then | |
mouseAction := maStats; | |
if (mouseAction = maRectangularROI) or (mouseAction = maLineProfile) or | |
(mouseAction = maStats) or (mouseAction = maEllipticROI) then | |
begin | |
anchorX := X; | |
anchorY := Y; | |
prevX := X; | |
prevY := Y; | |
with Canvas do | |
begin | |
Pen.Color := clWhite; | |
Pen.Style := psDot; | |
Pen.Mode := pmXor; | |
Pen.Width := 1; | |
end; | |
if mouseAction <> maEllipticROI then | |
Canvas.Polyline([Point(AnchorX, AnchorY), Point(AnchorX, prevY), Point(prevX, prevY), | |
Point(prevX, AnchorY), Point(AnchorX, AnchorY)]) | |
else | |
Canvas.Arc(AnchorX, AnchorY, X, Y, AnchorX, AnchorY, AnchorX, AnchorY); | |
end; | |
end; | |
end | |
else | |
begin | |
mouseAction := maNormal; | |
if not WindowToChannel(X, Y, currentChannel) then currentChannel := -1; | |
end; | |
end; | |
procedure TViewerFrm.FormMouseMove(Sender: TObject; Shift: TShiftState; X, | |
Y: Integer); | |
var xData, yData, pixelValue: integer; | |
roiIndex: integer; | |
begin | |
if mpFile = nil then Exit; | |
if WindowToChannel(X, Y, currentChannel) then | |
begin | |
if mpFile.VideoChEnabled[currentChannel] then | |
begin | |
StatusBar1.Panels[1].Text := 'Ch' + IntToStr(currentChannel + 1); | |
xData := WindowToFrameX(currentChannel, X); | |
yData := WindowToFrameY(Y); | |
pixelValue := mpFile.GetPixelValue(CurrentFrameIndex, currentChannel, xData, yData); | |
StatusBar1.Panels[2].Text := 'X: ' + IntToStr(xData); | |
StatusBar1.Panels[3].Text := 'Y: ' + IntToStr(yData); | |
StatusBar1.Panels[4].Text := 'Pixel: ' + IntToStr(pixelValue); | |
end | |
end | |
else | |
currentChannel := -1; | |
if (mouseAction = maRectangularROI) or (mouseAction = maStats) then | |
begin | |
Canvas.Polyline([Point(AnchorX, AnchorY), Point(AnchorX, prevY), Point(prevX, prevY), | |
Point(prevX, AnchorY), Point(AnchorX, AnchorY)]); | |
prevX := X; prevY := Y; | |
Canvas.Polyline([Point(AnchorX, AnchorY), Point(AnchorX, prevY), Point(prevX, prevY), | |
Point(prevX, AnchorY), Point(AnchorX, AnchorY)]); | |
end | |
else if mouseAction = maEllipticROI then | |
begin | |
Canvas.Arc(AnchorX, AnchorY, prevX, prevY, AnchorX, AnchorY, AnchorX, AnchorY); | |
prevX := X; prevY := Y; | |
Canvas.Arc(AnchorX, AnchorY, prevX, prevY, AnchorX, AnchorY, AnchorX, AnchorY); | |
end | |
else if mouseAction = maLineProfile then | |
begin | |
Canvas.Polyline([Point(AnchorX, AnchorY), Point(prevX, prevY)]); | |
prevX := X; prevY := Y; | |
Canvas.Polyline([Point(AnchorX, AnchorY), Point(prevX, prevY)]); | |
end | |
else if mouseAction = maNormal then | |
if currentChannel >= 0 then | |
begin | |
roiPt.x := WindowToFrameX(currentChannel, X); | |
roiPt.y := WindowToFrameY(Y); | |
roiIndex := ROIList.ROIOfPt(currentChannel, roiPt); | |
if roiIndex > - 1 then | |
StatusBar1.Panels[5].Text := 'ROI: ' + IntToStr(roiIndex + 1) | |
else | |
StatusBar1.Panels[5].Text := 'ROI:'; | |
end; | |
end; | |
const | |
sCreateOtherChROI = 'Do you want to create the same ROI in the other channels?'; | |
procedure TViewerFrm.FormMouseUp(Sender: TObject; Button: TMouseButton; | |
Shift: TShiftState; X, Y: Integer); | |
var rc: TRect; | |
otherChannel: integer; | |
begin | |
if mouseAction = maRectangularROI then | |
begin | |
mouseAction := maNormal; | |
CreateRectangularROI1Click(nil); {reset to normal mode} | |
ClipCursor(nil); | |
rc.Left := WindowToFrameX(currentChannel, anchorX); | |
rc.Right := WindowToFrameX(currentChannel, X); | |
rc.Top := WindowToFrameY(anchorY); | |
rc.Bottom := WindowToFrameY(Y); | |
ROIList.AddRectangularROI(currentChannel, rc); | |
SelectROIPlot(False, ROIList.Count - 1); | |
if mpFile.VideoChCount >= 2 then | |
if MessageDlg(sCreateOtherChROI, mtInformation, [mbOK, mbCancel], 0) = mrOK then | |
for otherChannel := 0 to MAX_CH - 1 do | |
if mpFile.VideoChEnabled[otherChannel] and (otherChannel <> currentChannel) then | |
begin | |
ROIList.AddRectangularROI(otherChannel, rc); | |
SelectROIPlot(False, ROIList.Count - 1); | |
end; | |
OnNewFrame; | |
HideROIs1.Enabled := True; | |
PlotROIofObjects1.Enabled := True; | |
DeleteallObjects1.Enabled := True; | |
end | |
else if mouseAction = maEllipticROI then | |
begin | |
mouseAction := maNormal; | |
CreateEllipticalROI1Click(nil); {reset to normal mode} | |
ClipCursor(nil); | |
rc.Left := WindowToFrameX(currentChannel, anchorX); | |
rc.Right := WindowToFrameX(currentChannel, X); | |
rc.Top := WindowToFrameY(anchorY); | |
rc.Bottom := WindowToFrameY(Y); | |
ROIList.AddEllipticalROI(currentChannel, rc); | |
SelectROIPlot(False, ROIList.Count - 1); | |
if mpFile.VideoChCount >= 2 then | |
if MessageDlg(sCreateOtherChROI, mtInformation, [mbOK, mbCancel], 0) = mrOK then | |
for otherChannel := 0 to MAX_CH - 1 do | |
if mpFile.VideoChEnabled[otherChannel] and (otherChannel <> currentChannel) then | |
begin | |
ROIList.AddEllipticalROI(otherChannel, rc); | |
SelectROIPlot(False, ROIList.Count - 1); | |
end; | |
OnNewFrame; | |
HideROIs1.Enabled := True; | |
PlotROIofObjects1.Enabled := True; | |
DeleteallObjects1.Enabled := True; | |
end | |
else if mouseAction = maLineProfile then | |
begin | |
mouseAction := maNormal; | |
ClipCursor(nil); | |
Canvas.Polyline([Point(AnchorX, AnchorY), Point(prevX, prevY)]); | |
rc.Left := WindowToFrameX(currentChannel, anchorX); | |
rc.Right := WindowToFrameX(currentChannel, X); | |
rc.Top := WindowToFrameY(anchorY); | |
rc.Bottom := WindowToFrameY(Y); | |
PlotLineProfile(currentChannel, rc); | |
CreateLineProfile1Click(nil); {reset to normal mode} | |
end | |
else if mouseAction = maStats then | |
begin | |
AreaStats1Click(nil); | |
mouseAction := maNormal; | |
ClipCursor(nil); | |
{erase rectangle} | |
Canvas.Polyline([Point(AnchorX, AnchorY), Point(AnchorX, prevY), Point(prevX, prevY), | |
Point(prevX, AnchorY), Point(AnchorX, AnchorY)]); | |
rc.Left := WindowToFrameX(currentChannel, anchorX); | |
rc.Right := WindowToFrameX(currentChannel, X); | |
rc.Top := WindowToFrameY(anchorY); | |
rc.Bottom := WindowToFrameY(Y); | |
StatDlg.Initialize(mpFile, CurrentFrameIndex, currentChannel, rc); | |
StatDlg.ShowModal; | |
end | |
else if mouseAction = maNormal then | |
if currentChannel >= 0 then | |
begin | |
roiPt.x := WindowToFrameX(currentChannel, X); | |
roiPt.y := WindowToFrameY(Y); | |
end; | |
end; | |
procedure TViewerFrm.FormDblClick(Sender: TObject); | |
var roiIndex: integer; | |
begin | |
if (mouseAction = maNormal) and (currentChannel >= 0) then | |
begin | |
roiIndex := ROIList.ROIOfPt(currentChannel, roiPt); | |
if roiIndex > - 1 then | |
SelectROIPlot(False, roiIndex); | |
end; | |
end; | |
procedure TViewerFrm.CreateLineProfile1Click(Sender: TObject); | |
begin | |
CreateLineProfile1.Checked := not CreateLineProfile1.Checked; | |
ToolButton9.Down := CreateLineProfile1.Checked; | |
end; | |
procedure TViewerFrm.CopyFrames1Click(Sender: TObject); | |
var fromFrame, toFrame, chIndex: integer; | |
s: string; | |
begin | |
if CheckNoFrame then Exit; | |
with MTransferDlg do | |
begin | |
InitGUI(mpFile); | |
SpinEdit1.MinValue := 1; | |
SpinEdit2.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := CurrentFrameIndex + 1; | |
SpinEdit2.Value := CurrentFrameIndex + 1; | |
ListBox1.ItemIndex := 0; | |
if MTransferDlg.ShowModal = mrOK then | |
begin | |
fromFrame := SpinEdit1.Value - 1; | |
toFrame := SpinEdit2.Value - 1; | |
if ListBox1.ItemIndex = 0 then s := 'base' else s := 'workspace'; | |
chIndex := SelectedCh; | |
if (fromFrame >= 0) and (fromFrame < mpFile.FrameCount) and | |
(toFrame >= 0) and (toFrame < mpFile.FrameCount) and | |
(SpinEdit3.Value > 0) and (fromFrame <= toFrame) then | |
ExportToMatlab(chIndex, fromFrame, toFrame, Edit1.Text, SpinEdit3.Value, | |
s) | |
else | |
MessageDlg('Invalid parameters.', mtError, [mbOK], 0); | |
end; | |
end; | |
end; | |
procedure TViewerFrm.AutomaticBackgroundCorrection1Click(Sender: TObject); | |
begin | |
if CheckNoFrame then Exit; | |
AutomaticBackgroundCorrection1.Checked := not AutomaticBackgroundCorrection1.Checked; | |
mpFile.DoBackgroundCorrection; | |
DrawFrame; | |
end; | |
procedure TViewerFrm.AreaStats1Click(Sender: TObject); | |
begin | |
if mouseAction = maNormal then | |
AreaStats1.Checked := True | |
else if mouseAction = maStats then | |
AreaStats1.Checked := False; | |
end; | |
procedure TViewerFrm.ExportFramesasamultipageTIFFfile1Click( | |
Sender: TObject); | |
var chIndex, fromFrame, toFrame: integer; | |
oldCursor: TCursor; | |
bNoNegativeValues: boolean; | |
begin | |
if CheckNoFrame then Exit; | |
with AVIOptDlg do | |
begin | |
InitGUI(mpFile); | |
SpinEdit1.MinValue := 1; | |
SpinEdit2.MinValue := 1; | |
SpinEdit1.MaxValue := mpFile.FrameCount; | |
SpinEdit2.MaxValue := mpFile.FrameCount; | |
SpinEdit1.Value := 1; | |
SpinEdit2.Value := mpFile.FrameCount; | |
Caption := 'Export as TIFF file'; | |
RadioButton5.Checked := True; | |
GroupBox2.Enabled := False; | |
Label2.Visible := False; | |
SpinEdit3.Visible := False; | |
Label4.Visible := False; | |
end; | |
with SaveDialog1 do | |
begin | |
DefaultExt := 'TIF'; | |
Filter := 'TIFF Files (*.TIF)|*.TIF|All Files (*.*)|*.*'; | |
Title := 'Export as TIFF file'; | |
if Execute then | |
if AVIOptDlg.ShowModal = mrOK then | |
begin | |
chIndex := AVIOptDlg.SelectedCh; | |
fromFrame := AVIOptDlg.SpinEdit1.Value - 1; | |
toFrame := AVIOptDlg.SpinEdit2.Value - 1; | |
if (fromFrame >= 0) and (fromFrame < mpFile.FrameCount) and | |
(toFrame >= 0) and (toFrame < mpFile.FrameCount) | |
and (fromFrame <= toFrame) then | |
begin | |
oldCursor := Screen.Cursor; | |
try | |
Screen.Cursor := crHourGlass; | |
bNoNegativeValues := mpFile.MakeTIFF(SaveDialog1.Filename, chIndex, | |
fromFrame, toFrame); | |
Screen.Cursor := oldCursor; | |
if not bNoNegativeValues then | |
MessageDlg('Negative pixel values changed to 0.', | |
mtWarning, [mbOK], 0); | |
MessageDlg('Successfully exported frames in TIFF file.', | |
mtInformation, [mbOK], 0); | |
except | |
Screen.Cursor := oldCursor; | |
MessageDlg('Error in creating TIFF file.', | |
mtError, [mbOK], 0); | |
end; | |
end | |
else | |
MessageDlg('Invalid frames', mtError, [mbOK], 0); | |
end; | |
end; | |
end; | |
procedure TViewerFrm.CustomColors1Click(Sender: TObject); | |
begin | |
if CustomColors1.Checked then Exit; | |
CustomColors1.Checked := True; | |
colorScheme := CS_CUSTOMLUT; | |
FalseColors1.Checked := False; | |
GrayScale1.Checked := False; | |
MakeColorScale; | |
DrawFrame; | |
end; | |
procedure TViewerFrm.FalseColors1Click(Sender: TObject); | |
begin | |
if FalseColors1.Checked then Exit; | |
FalseColors1.Checked := True; | |
colorScheme := CS_FALSECOLORS; | |
CustomColors1.Checked := False; | |
GrayScale1.Checked := False; | |
MakeColorScale; | |
DrawFrame; | |
end; | |
procedure TViewerFrm.CustomColorsLookupTable1Click(Sender: TObject); | |
begin | |
LUTDlg := TLUTDlg.Create(Mainform); | |
with LUTDlg, mpFile do | |
begin | |
viewer := Self; | |
dlgBaseColors := baseColors; | |
dlgnegativeColors := negativeColors; | |
dlgmidRangeColors := midRangeColors; | |
dlgmaxColors := maxColors; | |
dlgMaxPixels := maxPixels; | |
end; | |
if LUTDlg.ShowModal = mrOK then | |
begin | |
SetLUTColors; | |
if colorScheme <> CS_CUSTOMLUT then | |
CustomColors1Click(nil); | |
LUTDlg.Free; | |
Invalidate; | |
end | |
else | |
LUTDlg.Free; | |
end; | |
procedure TViewerFrm.PaintBox1Paint(Sender: TObject); | |
begin | |
MakeColorScale; | |
end; | |
procedure TViewerFrm.BinaryFrameOperations1Click(Sender: TObject); | |
begin | |
if not Mainform.bBinaryOp then | |
if Mainform.fileList.WorkspaceCount = 0 then | |
MessageDlg('No workspace to store result frame.', mtError, [mbOK], 0) | |
else | |
begin | |
BinOpForm := TBinOpForm.Create(mainform); | |
BinOpForm.Show; | |
Mainform.bBinaryOp := True; | |
end; | |
end; | |
procedure TViewerFrm.OverlayCh1onCh21Click(Sender: TObject); | |
begin | |
OverlayCh1onCh21.Checked := not OverlayCh1onCh21.Checked; | |
DrawFrame; | |
end; | |
procedure TViewerFrm.OverlayCh2onCh31Click(Sender: TObject); | |
begin | |
OverlayCh2onCh31.Checked := not OverlayCh2onCh31.Checked; | |
DrawFrame; | |
end; | |
end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment