📄 streamer.h
字号:
if (XferThread->ThreadState == System::Threading::ThreadState::Running)
XferThread->Join(10);
}
void StartBtn_Click(System::Object * sender, System::EventArgs * e)
{
Decimal db;
if(!Decimal::TryParse(this->TimeOutBox->Text, &db))
{
::MessageBox(NULL,"Invalid Input : TimeOut Per Xfer(ms)","Streamer",0);
this->TimeOutBox->Text = "";
return;
}
if (XferThread) {
switch (XferThread->ThreadState)
{
case System::Threading::ThreadState::Stopped:
case System::Threading::ThreadState::Unstarted:
EnforceValidPPX();
StartBtn->Text = "Stop";
StartBtn->BackColor = Color::MistyRose;
StartBtn->Refresh();
bStreaming = true;
// Start-over, initializing counters, etc.
if ((XferThread->ThreadState) == System::Threading::ThreadState::Stopped)
XferThread = new Thread(new ThreadStart(0,&XferLoop));
PPX = Convert::ToInt32(PacketsPerXferBox->Text);
QueueSize = Convert::ToInt32(QueueLenBox->Text);
TimeOut = Convert::ToInt32(TimeOutBox->Text);
bShowData = ShowDataBox->Checked;
EndPointsBox->Enabled = false;
PacketsPerXferBox->Enabled = false;
QueueLenBox->Enabled = false;
TimeOutBox->Enabled = false;
ShowDataBox->Enabled = false;
XferThread->Start();
break;
case System::Threading::ThreadState::Running:
StartBtn->Text = "Start";
StartBtn->BackColor = Color::Aquamarine;
StartBtn->Refresh();
bStreaming = false; // Stop the thread's xfer loop
XferThread->Join(10);
EndPointsBox->Enabled = true;
PacketsPerXferBox->Enabled = true;
QueueLenBox->Enabled = true;
TimeOutBox->Enabled = true;
ShowDataBox->Enabled = true;
break;
}
}
}
void EndPointsBox_SelectedIndexChanged(System::Object * sender, System::EventArgs * e)
{
// Parse the alt setting and endpoint address from the EndPointsBox->Text
String *tmp = EndPointsBox->Text->Substring(EndPointsBox->Text->IndexOf("("),10);
int alt = Convert::ToInt32(tmp->Substring(1,1));
String *addr = tmp->Substring(7,2);
//changed int to __int64 to avoid data loss
__int64 eptAddr = HexToInt(addr);
int clrAlt = (USBDevice->AltIntfc() == 0) ? 1 : 0;
// Attempt to set the selected Alt setting and get the endpoint
if (! USBDevice->SetAltIntfc(alt))
{
MessageBox::Show("Alt interface could not be selected.","USB Exception",MessageBoxButtons::OK,MessageBoxIcon::Hand);
StartBtn->Enabled = false;
USBDevice->SetAltIntfc(clrAlt); // Cleans-up
return;
}
EndPt = USBDevice->EndPointOf((UCHAR)eptAddr);
StartBtn->Enabled = true;
if (EndPt->Attributes == 1)
{
SuccessLabel->Text = "Good Pkts";
FailureLabel->Text = "Bad Pkts";
}
else
{
SuccessLabel->Text = "Successes";
FailureLabel->Text = "Failures";
}
EnforceValidPPX();
}
void EnforceValidPPX()
{
PPX = Convert::ToInt32(PacketsPerXferBox->Text);
// Limit total transfer length to 64K
int len = ((EndPt->MaxPktSize) * PPX);
int maxLen = 0x10000;
if (len > maxLen)
{
PPX = maxLen / EndPt->MaxPktSize;
DataBox->Text = String::Concat(DataBox->Text,"Total xfer length limited to 64K.\r\n");
DataBox->Text = String::Concat(DataBox->Text,"Packets per Xfer has been adjusted.\r\n");
DataBox->SelectionStart = DataBox->Text->Length;
DataBox->ScrollToCaret();
}
if (bHighSpeedDevice && (EndPt->Attributes == 1)) // HS ISOC Xfers must use PPX >= 8
{
if (PPX < 8)
{
PPX = 8;
Display("ISOC xfers require at least 8 Packets per Xfer.");
Display("Packets per Xfer has been adjusted.");
}
PPX = (PPX / 8) * 8;
}
PacketsPerXferBox->Text = PPX.ToString();
}
static UInt64 HexToInt(String *hexString)
{
String *HexChars = "0123456789abcdef";
String *s = hexString->ToLower();
// Trim off the 0x prefix
if (s->Length > 2)
if (s->Substring(0,2)->Equals("0x"))
s = s->Substring(2,s->Length-2);
String *_s = "";
int len = s->Length;
// Reverse the digits
for (int i=len-1; i>=0; i--) _s = String::Concat(_s,s->Substring(i,1));
UInt64 sum = 0;
UInt64 pwrF = 1;
for (int i=0; i<len; i++)
{
UInt32 ordinal = (UInt32) HexChars->IndexOf(_s->Substring(i,1));
sum += (i==0) ? ordinal : pwrF*ordinal;
pwrF *= 16;
}
return sum;
}
static void ShowCpuLoad(Object* state)
{
Form1 *form = dynamic_cast<Form1 *>(state);
if (form->CPUCounter != NULL)
{
//thread safe-commented
CheckForIllegalCrossThreadCalls = false;
float load = form->CPUCounter->NextValue();
int a = Convert::ToInt32(load);
form->CPUBar->Value = a;
form->CPULabel->Text = String::Concat(a.ToString()," %");
}
}
static void Display(String *s)
{
DataBox->Text = String::Concat(DataBox->Text, s, "\r\n");
DataBox->SelectionStart = DataBox->Text->Length;
DataBox->ScrollToCaret();
}
static void Display16Bytes(PUCHAR data)
{
String *xData = "";
for (int i=0; i<16; i++)
xData = String::Concat(xData,data[i].ToString("X02"), " ");
Display(xData);
}
// This method executes in it's own thread. The thread gets re-launched each time the
// Start button is clicked (and the thread isn't already running).
static void XferLoop()
{
long BytesXferred = 0;
unsigned long Successes = 0;
unsigned long Failures = 0;
int i = 0;
// Allocate the arrays needed for queueing
PUCHAR *buffers = new PUCHAR[QueueSize];
CCyIsoPktInfo **isoPktInfos = new CCyIsoPktInfo*[QueueSize];
PUCHAR *contexts = new PUCHAR[QueueSize];
OVERLAPPED inOvLap[MAX_QUEUE_SZ];
long len = EndPt->MaxPktSize * PPX; // Each xfer request will get PPX isoc packets
EndPt->SetXferSize(len);
// Allocate all the buffers for the queues
for (i=0; i< QueueSize; i++)
{
buffers[i] = new UCHAR[len];
isoPktInfos[i] = new CCyIsoPktInfo[PPX];
inOvLap[i].hEvent = CreateEvent(NULL, false, false, NULL);
memset(buffers[i],0,len);
}
DateTime t1 = DateTime::Now; // For calculating xfer rate
// Queue-up the first batch of transfer requests
for (i=0; i< QueueSize; i++)
{
contexts[i] = EndPt->BeginDataXfer(buffers[i], len, &inOvLap[i]);
if (EndPt->NtStatus || EndPt->UsbdStatus) // BeginDataXfer failed
{
Display(String::Concat("Xfer request rejected. NTSTATUS = ",EndPt->NtStatus.ToString("x")));
AbortXferLoop(i+1, buffers,isoPktInfos,contexts,inOvLap);
return;
}
}
i=0;
// The infinite xfer loop.
for (;bStreaming;)
{
long rLen = len; // Reset this each time through because
// FinishDataXfer may modify it
if (!EndPt->WaitForXfer(&inOvLap[i], TimeOut))
{
EndPt->Abort();
if (EndPt->LastError == ERROR_IO_PENDING)
WaitForSingleObject(inOvLap[i].hEvent,2000);
}
if (EndPt->Attributes == 1) // ISOC Endpoint
{
if (EndPt->FinishDataXfer(buffers[i], rLen, &inOvLap[i], contexts[i], isoPktInfos[i]))
{
CCyIsoPktInfo *pkts = isoPktInfos[i];
for (int j=0; j< PPX; j++)
{
if (pkts[j].Status == 0)
{
BytesXferred += pkts[j].Length;
if (bShowData)
Display16Bytes(buffers[i]);
Successes++;
}
else
Failures++;
pkts[j].Length = 0; // Reset to zero for re-use.
}
}
else
Failures++;
}
else // BULK Endpoint
{
if (EndPt->FinishDataXfer(buffers[i], rLen, &inOvLap[i], contexts[i]))
{
Successes++;
BytesXferred += len;
if (bShowData)
Display16Bytes(buffers[i]);
}
else
Failures++;
}
if (BytesXferred < 0) // Rollover - reset counters
{
BytesXferred = 0;
t1 = DateTime::Now;
}
// Re-submit this queue element to keep the queue full
contexts[i] = EndPt->BeginDataXfer(buffers[i], len, &inOvLap[i]);
if (EndPt->NtStatus || EndPt->UsbdStatus) // BeginDataXfer failed
{
Display(String::Concat("Xfer request rejected. NTSTATUS = ",EndPt->NtStatus.ToString("x")));
AbortXferLoop(QueueSize,buffers,isoPktInfos,contexts,inOvLap);
return;
}
i++;
if (i == QueueSize) //Only update the display once each time through the Queue
{
i=0;
ShowStats(t1, BytesXferred, Successes, Failures);
}
} // End of the infinite loop
// Memory clean-up
AbortXferLoop(QueueSize,buffers,isoPktInfos,contexts,inOvLap);
}
static void AbortXferLoop(int pending, PUCHAR *buffers, CCyIsoPktInfo **isoPktInfos, PUCHAR *contexts, OVERLAPPED inOvLap __nogc [])
{
EndPt->Abort();
long len = EndPt->MaxPktSize * PPX;
for (int j=0; j< QueueSize; j++)
{
if (j<pending)
{
if (!EndPt->WaitForXfer(&inOvLap[j], TimeOut))
{
EndPt->Abort();
if (EndPt->LastError == ERROR_IO_PENDING)
WaitForSingleObject(inOvLap[j].hEvent,2000);
}
EndPt->FinishDataXfer(buffers[j], len, &inOvLap[j], contexts[j]);
}
CloseHandle(inOvLap[j].hEvent);
delete [] buffers[j];
delete [] isoPktInfos[j];
}
delete [] buffers;
delete [] isoPktInfos;
delete [] contexts;
bStreaming = false;
StartButton->Text = "Start";
StartButton->BackColor = Color::Aquamarine;
StartButton->Refresh();
EptsBox->Enabled = true;
PpxBox->Enabled = true;
QueueBox->Enabled = true;
TimeoutBox->Enabled = true;
ShowBox->Enabled = true;
}
static void ShowStats(DateTime t, long bytesXferred, unsigned long successes, unsigned long failures)
{
TimeSpan elapsed = DateTime::Now.Subtract(t);
long totMS = (long)elapsed.TotalMilliseconds;
if (totMS <= 0) return;
long XferRate = bytesXferred / totMS;
// Convert to KB/s
XferRate = XferRate * 1000 / 1024;
// Truncate last 1 or 2 digits
int rounder = (XferRate > 2000) ? 100 : 10;
XferRate = XferRate / rounder * rounder;
//thread safe-commented
CheckForIllegalCrossThreadCalls = false;
if (XferRate > XferRateBar->Maximum)
XferRate = XferRateBar->Maximum;
XferRateBar->Value = XferRate;
XferRateLabel->Text = XferRate.ToString();
SuccessBox->Text = successes.ToString();
FailureBox->Text = failures.ToString();
}
protected:
[System::Security::Permissions::PermissionSet(System::Security::Permissions::SecurityAction::Demand, Name="FullTrust")]
virtual void WndProc(Message *m)
{
if (m->Msg == WM_DEVICECHANGE)
{
// Tracks DBT_DEVNODES_CHANGED followed by DBT_DEVICEREMOVECOMPLETE
if (m->WParam == DBT_DEVNODES_CHANGED)
{
bPnP_DevNodeChange = true;
bPnP_Removal = false;
}
// Tracks DBT_DEVICEARRIVAL followed by DBT_DEVNODES_CHANGED
if (m->WParam == DBT_DEVICEARRIVAL)
{
bPnP_Arrival = true;
bPnP_DevNodeChange = false;
}
if (m->WParam == DBT_DEVICEREMOVECOMPLETE)
bPnP_Removal = true;
// If DBT_DEVICEARRIVAL followed by DBT_DEVNODES_CHANGED
if (bPnP_DevNodeChange && bPnP_Removal)
{
bPnP_Removal = false;
bPnP_DevNodeChange = false;
bStreaming = false;
GetStreamerDevice();
}
// If DBT_DEVICEARRIVAL followed by DBT_DEVNODES_CHANGED
if (bPnP_DevNodeChange && bPnP_Arrival)
{
bPnP_Arrival = false;
bPnP_DevNodeChange = false;
GetStreamerDevice();
}
}
Form::WndProc(m);
}
void Dispose(Boolean disposing)
{
if (disposing && components)
{
components->Dispose();
}
__super::Dispose(disposing);
}
};
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -