How to use Frame Rate convertor DMO in MF app - directshow

I wish to use the Frame Rate convertor DSP in my media foundation application. I'm using the 'SourceReader' to read the video file. Can anyone tell me where and how to integrate the DMO with MF to obtain frame rate conversion. I don't seem to understand what kind of samples (compressed/uncompressed) to feed to the DMO to obtain new frame rate. How does the DMO change the frame rate? Does it give a new time-stamp to the new samples? There are no code examples demonstrating its use. Please help, I'm stuck.
Thanks,
Mots

It is an old question.
To do frame rate conversion with the SourceReader, we need to integrate the DMO manually.
The idea is to get compatible sample from the SourceReader, let say a video subtype handled by the DMO.
How does the DMO change the frame rate?
According to the Frame Rate Converter DSP :
This DSP changes the frame rate by repeating or dropping frames.
.
Does it give a new time-stamp to the new samples?
The DMO changes sample time and sample duration. But if the duration of the video file is 1 minute, it will remain the same at the end.
For example, if your video file has 1800 frames, a duration of 1 minute and a frame rate of 30 frames/second. You want 60 frames/second, so you will have 3600 frames and the duration doesn't change (always 1 minute).
#pragma once
#define WIN32_LEAN_AND_MEAN
#define STRICT
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfreadwrite")
#pragma comment(lib, "mfuuid")
#pragma comment(lib, "wmcodecdspuuid")
#include <WinSDKVer.h>
#include <new>
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <mferror.h>
#include <Wmcodecdsp.h>
template <class T> inline void SAFE_RELEASE(T*& p){
if(p){
p->Release();
p = NULL;
}
}
HRESULT ProcessConverter();
HRESULT InitDMO(IMFTransform**, IMFMediaType*);
HRESULT ProcessSample(IMFSourceReader*, IMFTransform*);
HRESULT ProcessDMO(IMFTransform*, IMFSample*, DWORD&, const UINT32);
HRESULT InitOutputDataBuffer(IMFTransform*, MFT_OUTPUT_DATA_BUFFER*, const UINT32);
void main(){
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if(SUCCEEDED(hr)){
hr = MFStartup(MF_VERSION, MFSTARTUP_LITE);
if(SUCCEEDED(hr)){
hr = ProcessConverter();
hr = MFShutdown();
}
CoUninitialize();
}
}
HRESULT ProcessConverter(){
HRESULT hr;
IMFSourceReader* pReader = NULL;
// Change the URL
if(FAILED(hr = MFCreateSourceReaderFromURL(L"Wildlife.wmv", NULL, &pReader))){
return hr;
}
DWORD dwMediaTypeIndex = 0;
IMFMediaType* pType = NULL;
hr = pReader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, dwMediaTypeIndex, &pType);
if(SUCCEEDED(hr)){
// We must ask for a subtype compatible with DMO :
// ARGB32 RGB24 RGB32 RGB555 RGB565 AYUV IYUV UYVY Y211 Y411 Y41P YUY2 YUYV YV12 YVYU
hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12);
if(SUCCEEDED(hr)){
hr = pReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pType);
}
// We need this because we use the MediaType to initialize the Transform
if(SUCCEEDED(hr)){
SAFE_RELEASE(pType);
hr = pReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pType);
}
if(SUCCEEDED(hr)){
IMFTransform* pTransform = NULL;
hr = InitDMO(&pTransform, pType);
if(SUCCEEDED(hr)){
hr = ProcessSample(pReader, pTransform);
// Seems not really needed with the DMO
/*hr = */ pTransform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, NULL);
/*hr = */ pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, NULL);
/*hr = */ pTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, NULL);
}
SAFE_RELEASE(pTransform);
}
}
SAFE_RELEASE(pType);
SAFE_RELEASE(pReader);
return hr;
}
HRESULT InitDMO(IMFTransform** ppTransform, IMFMediaType* pType){
HRESULT hr = CoCreateInstance(CLSID_CFrameRateConvertDmo, NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, reinterpret_cast<void**>(ppTransform));
if(SUCCEEDED(hr)){
hr = (*ppTransform)->SetInputType(0, pType, 0);
}
if(SUCCEEDED(hr)){
// Change the frame rate as needed, here num = 60000 and den = 1001
hr = MFSetAttributeRatio(pType, MF_MT_FRAME_RATE, 60000, 1001);
}
if(SUCCEEDED(hr)){
hr = (*ppTransform)->SetOutputType(0, pType, 0);
}
if(SUCCEEDED(hr)){
hr = (*ppTransform)->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
}
if(SUCCEEDED(hr)){
hr = (*ppTransform)->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL);
}
return hr;
}
HRESULT ProcessSample(IMFSourceReader* pReader, IMFTransform* pTransform){
HRESULT hr;
IMFMediaType* pType = NULL;
if(FAILED(hr = pTransform->GetOutputCurrentType(0, &pType))){
return hr;
}
// We need the frame size to create the sample buffer.
UINT32 uiFrameSize = 0;
hr = pType->GetUINT32(MF_MT_SAMPLE_SIZE, &uiFrameSize);
SAFE_RELEASE(pType);
if(FAILED(hr) || uiFrameSize == 0){
return hr;
}
BOOL bProcess = TRUE;
DWORD streamIndex;
DWORD flags;
LONGLONG llTimeStamp;
IMFSample* pSample = NULL;
DWORD dwReaderCount = 0;
DWORD dwDMOCount = 0;
while(bProcess){
hr = pReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, &streamIndex, &flags, &llTimeStamp, &pSample);
if(FAILED(hr) || flags != 0){
bProcess = FALSE;
}
else{
hr = ProcessDMO(pTransform, pSample, dwDMOCount, uiFrameSize);
// You can check timestamp from the SourceReader
//hr = pSample->GetSampleDuration(&llTimeStamp);
//hr = pSample->GetSampleTime(&llTimeStamp);
SAFE_RELEASE(pSample);
dwReaderCount++;
}
}
// Todo : check dwReaderCount and dwDMOCount here.
// For example with native frame rate = 30000/1001 and dwReaderCount = 900
// DMO frame rate = 30000/1001 -> dwReaderCount = 900
// DMO frame rate = 60000/1001 -> dwReaderCount = 1800
// DMO frame rate = 25/1 -> dwReaderCount = 750
SAFE_RELEASE(pSample);
return hr;
}
HRESULT ProcessDMO(IMFTransform* pTransform, IMFSample* pSample, DWORD& dwDMOCount, const UINT32 uiFrameSize){
HRESULT hr = S_OK;
MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
DWORD processOutputStatus = 0;
// Todo : we should avoid recreating the buffer...
hr = InitOutputDataBuffer(pTransform, &outputDataBuffer, uiFrameSize);
while(hr == S_OK){
hr = pTransform->ProcessOutput(0, 1, &outputDataBuffer, &processOutputStatus);
if(hr == MF_E_TRANSFORM_NEED_MORE_INPUT){
break;
}
// You can check new timestamp from the DMO
/*if(outputDataBuffer.pSample != NULL){
LONGLONG llTimeStamp = 0;
hr = outputDataBuffer.pSample->GetSampleTime(&llTimeStamp);
hr = outputDataBuffer.pSample->GetSampleDuration(&llTimeStamp);
}*/
dwDMOCount++;
}
if(hr == MF_E_TRANSFORM_NEED_MORE_INPUT){
hr = pTransform->ProcessInput(0, pSample, 0);
}
if(outputDataBuffer.pSample != NULL){
SAFE_RELEASE(outputDataBuffer.pSample);
}
return hr;
}
HRESULT InitOutputDataBuffer(IMFTransform* pMFTransform, MFT_OUTPUT_DATA_BUFFER* pOutputBuffer, const UINT32 uiFrameSize){
MFT_OUTPUT_STREAM_INFO outputStreamInfo;
DWORD outputStreamId = 0;
ZeroMemory(&outputStreamInfo, sizeof(outputStreamInfo));
ZeroMemory(pOutputBuffer, sizeof(*pOutputBuffer));
HRESULT hr = pMFTransform->GetOutputStreamInfo(outputStreamId, &outputStreamInfo);
if(SUCCEEDED(hr)){
if((outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) == 0 &&
(outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) == 0){
IMFSample* pOutputSample = NULL;
IMFMediaBuffer* pMediaBuffer = NULL;
hr = MFCreateSample(&pOutputSample);
if(SUCCEEDED(hr)){
hr = MFCreateMemoryBuffer(uiFrameSize, &pMediaBuffer);
}
if(SUCCEEDED(hr)){
hr = pOutputSample->AddBuffer(pMediaBuffer);
}
if(SUCCEEDED(hr)){
pOutputBuffer->pSample = pOutputSample;
pOutputBuffer->pSample->AddRef();
}
SAFE_RELEASE(pMediaBuffer);
SAFE_RELEASE(pOutputSample);
}
}
return hr;
}

Related

Arduino / DigiSpark / ATtiny85 - Receiving and parsing several pieces of data

i'm trying to make a digispark to work with bluetooth and NeoPixel, while i had success into making it go on and off i would like to expand on it.
I have used the Robin2 example 5 method to reciece, and parse my data in order to get the leds color the way i want.
https://forum.arduino.cc/index.php?topic=396450.msg2727728#msg2727728
this is the code in my case - the original is in the link above
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
strip.setBrightness(xB);
controlLed();
newData = false;
}
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (bluetooth.available() > 0 && newData == false) {
rc = bluetooth.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
} else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
} else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ","); // get the first part - the string
eFx = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // get the first part - the string
rC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
gC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
bC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
xS = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
xB = atoi(strtokIndx); // convert this part to an integer
}
void controlLed() {
colorWipe(strip.Color(rC1, gC1, bC1), xS);
colorWipe(strip.Color(20, 50, 100), 50);
}
now i have some issues, as the ATtiny85 memory is not that great i ran into issues when i try to send longer strings, basically i want to send all these:
int eFx = 1;
int rC1 = 100;
int gC1 = 100;
int bC1 = 100;
int xS = 20;
int xB = 100;
int rC2 = 5;
int gC2 = 50;
int bC2 = 200;
but when i try to parse it with the strtokIndx method above the digispark stops working (when i add more to what is already shown in the code ex above) i guess it's due to memory issues.
i understand part of the code,but not well enough to expand it in the direction that i want.
Right now the way it works is that when i send via BTooth info in this format asd<1,24,23,54,...,>qwe the recvWithStartEndMarkers () will grab all there is between < > and store it (?) in receivedChars
then i'm not sure why and how parseData() grabs this string and not something else, is it because of the function in the loop?
strcpy(tempChars, receivedChars);
parseData();
Well, i want to try to make this process go at it again, to recieve another string under [ ] and not < > and parseData2() (maybe) on receivedChars2 to get my last 3 INTs (color values for NeoPixel) parsed and stored in order to use them without having the digispark crash out of memory
The first step would be to change the
void recvWithStartEndMarkers() {
to detect also de diffrence between < and [ and run the proper code in order to store either in receivedChars or receivedChars2
not sure how to do that, also i'm not sure if this would be useful and would solve my memory issues.
any thoughts?
here is the full code i'm running
#include <Adafruit_NeoPixel.h> // NeoPixel Lib
#include <SoftSerial.h> // Serial Lib
#define LED_PIN 2
#define LED_COUNT 30
SoftSerial bluetooth(4, 5); // RX TX
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
const byte numChars = 42;
char receivedChars[numChars];
char tempChars[numChars];
boolean newData = false;
int eFx = 1;
int rC1 = 100;
int gC1 = 100;
int bC1 = 100;
int xS = 20;
int xB = 100;
int rC2 = 5;
int gC2 = 50;
int bC2 = 200;
void setup() {
bluetooth.begin (9600);
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
strip.show(); // Turn OFF all pixels ASAP
}
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
strip.setBrightness(xB);
controlLed();
newData = false;
}
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (bluetooth.available() > 0 && newData == false) {
rc = bluetooth.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
} else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
} else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, ","); // get the first part - the string
eFx = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // get the first part - the string
rC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
gC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
bC1 = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
xS = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, ",");
xB = atoi(strtokIndx); // convert this part to an integer
}
void controlLed() {
colorWipe(strip.Color(rC1, gC1, bC1), xS);
colorWipe(strip.Color(20, 50, 100), 50);
}
void controlLed2() {
colorWipe(strip.Color(rC2, gC2, bC2), xS);
}
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}

Arduino Uno low memory available

i'm trying to do a communication over ethernet using ENC28J60 and Arduino Uno and run 3 task . I have a little problem with my arduino code. My code is compiling but i get the following error : "Low memory available, stability problems may occur." and the led on the board is blinking very fast. I guess that the board is trying to alocate memory but he faild. Any idea what can i do ?
#include <Arduino_FreeRTOS.h>
#include "HX711.h"
#include <PID_v1.h>
#include <string.h>
//#include <SPI.h>
#include <UIPEthernet.h>
#define configUSE_IDLE_HOOK 0
// FreeRTOS tasks
void TaskPrimaryControlLoop(void *pvParameters);
void TaskConcentrationControlLoop(void *pvParameters);
void TaskIdle(void *pvParameters);
/* Weigth Cells */
#define hx_pf_dout 3
#define hx_pf_clk 2
#define hx_c_dout 5
#define hx_c_clk 4
HX711 pf_scale(hx_pf_dout, hx_pf_clk);
HX711 c_scale(hx_c_dout, hx_c_clk);
float pf_factor = -236000;
float c_factor = -203000;
float p_weigth = 0; // (kg, 0.000) primary liquid weigth
float p_l_weigth = 0; // (kg, 0.000) primary liquid last weigth
float c_weigth = 0; // (kg, 0.000) concentrate liquid weigth
float c_l_weight = 0; // (kg, 0.000) concentrate liquid last weigth
/* h bridge config */
#define speed_p 9
#define forward_p 7
#define backward_p 8
#define speed_c 6
#define forward_c A0
#define backward_c A1
double p_pump = 0; // 0-255 pwm pump output
double c_pump = 0; // 0-255 pwm pump output
//// PID parameters
// Primary Control Loop
#define p_kp 250.0
#define p_ki 25.0
// Concentration Control Loop
#define c_kp 250.0
#define c_ki 25.0
double p_pv = 0; // (%) primary flow value
double c_pv = 0; // (%) concentration flow value
double p_sp = 0; // (l/min) primary flow setpoint
double c_sp_proc = 0; // % concentration
double c_sp = 0; // (l/min) concentration setpoint
PID pid_pcl(&p_pv, &p_pump, &p_sp, p_kp,p_ki,0.0, DIRECT);
PID pid_ccl(&c_pv, &c_pump, &c_sp, c_kp,c_ki,0.0, DIRECT);
/* Communication Ethernet */
#define MAX_STRING_LEN 32
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 2);
IPAddress myDns(192,168,1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
// telnet defaults to port 23
EthernetServer server(23);
//EthernetClient client;
boolean alreadyConnected = false; // whether or not the client was connected previously
void setup() {
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
}
pinMode(forward_p, OUTPUT);
pinMode(backward_p, OUTPUT);
pinMode(forward_c, OUTPUT);
pinMode(backward_c, OUTPUT);
pinMode(speed_p, OUTPUT);
pinMode(speed_c, OUTPUT);
digitalWrite(backward_p, HIGH);
digitalWrite(backward_c, HIGH);
digitalWrite(forward_p, LOW);
digitalWrite(forward_c, LOW);
pf_scale.set_scale(pf_factor);
c_scale.set_scale(c_factor);
//pf_scale.tare();
//c_scale.tare();
pid_ccl.SetMode(AUTOMATIC);
pid_pcl.SetMode(AUTOMATIC);
xTaskCreate(
TaskPrimaryControlLoop
, (const portCHAR *)"PrimaryControlLoop" // A name just for humans
, 128 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL );
xTaskCreate(
TaskConcentrationControlLoop
, (const portCHAR *)"ConcentrationControlLoop" // A name just for humans
, 128 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL );
xTaskCreate(
TaskIdle
, (const portCHAR *)"Idle" // A name just for humans
, 512 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 0 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL );
}
void loop() {
}
void TaskPrimaryControlLoop(void *pvParameters)
{
//(void) pvParameters;
for (;;)
{
p_weigth = pf_scale.get_units(1);
p_pv = (p_l_weigth - p_weigth)*100;
if(p_pv < 0) p_pv = 0;
pid_pcl.Compute();
analogWrite(speed_p, p_pump);
p_l_weigth = p_weigth;
vTaskDelay(200 / portTICK_PERIOD_MS); // 200 ms sample time
}
}
void TaskConcentrationControlLoop(void *pvParameters)
{
//(void) pvParameters;
for (;;)
{
c_weigth = c_scale.get_units(1);
c_pv = (c_l_weight - c_weigth)*100;
if(c_pv < 0) c_pv = 0;
c_sp = p_sp * (c_sp_proc/100);
pid_ccl.Compute();
analogWrite(speed_c, c_pump);
c_l_weight = c_weigth;
vTaskDelay(200 / portTICK_PERIOD_MS); // 200 ms sample time
}
}
void TaskIdle(void *pvParameters)
{
//(void) pvParameters;
for(;;){
EthernetClient client = server.available();
// when the client sends the first byte, say hello:
if (client) {
if (!alreadyConnected) {
client.flush();
//Serial.println("We have a new client");
//client.println("Hello, client!");
alreadyConnected = true;
}
}
recvWithStartEndMarkers();
//showNewData();
if(receivedChars[0] == 's'){
p_sp = atof(subStr(receivedChars, ",", 2));
c_sp_proc = int(subStr(receivedChars, ",", 3));
newData = false;
memset(receivedChars, 0, sizeof(receivedChars));
}
// send process values to application
if(receivedChars[0] == 'w'){
Serial.print(p_pv);
Serial.print(",");
Serial.print(p_sp);
Serial.print(",");
Serial.print(int(c_pump));
Serial.print(",");
Serial.print(c_pv);
Serial.print(",");
Serial.print(c_sp);
Serial.print(",");
Serial.print(int(p_pump));
Serial.println();
newData = false;
memset(receivedChars, 0, sizeof(receivedChars));
}
/*
// check commands
while(Serial.available() > 7){
p_sp = Serial.parseFloat();
c_sp_proc = Serial.parseInt();
}
newData = false;
memset(receivedChars, 0, sizeof(receivedChars)
*/
newData = false;
memset(receivedChars, 0, sizeof(receivedChars));
vTaskDelay(1);
}
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
EthernetClient client = server.available();
while (client.available() > 0 && newData == false) {
rc = client.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
// Function to return a substring defined by a delimiter at an index
char* subStr (char* str, char *delim, int index) {
char *act, *sub, *ptr;
static char copy[MAX_STRING_LEN];
int i;
// Since strtok consumes the first arg, make a copy
strcpy(copy, str);
for (i = 1, act = copy; i <= index; i++, act = NULL) {
//Serial.print(".");
sub = strtok_r(act, delim, &ptr);
if (sub == NULL) break;
}
return sub;
}
First thing to do is try to increase the stack depth of your Tasks.
You're currently using 128, 128 and 512.
You can use "StackHighWaterMark" to get the info about the amount of stack space remaining. Try to use this information to "calibrate" the depth of your task. I recommend using at least 40% of free space.
In order to save space in the Arduino memory you can put all the Serial.print in the flash memory, try to use this syntax:
Serial.print(F(","));
Basically you have to add an F in front of the string that you want to print, but you can't do that when you print a variable:
Serial.print(int(c_pump)); // you can't do that here

Doppler radar (HB100) Arduino code : Why do we use bit-shifting?

I've been working on my doppler radar speed project for a while. I found this very helpful link and the code below:
// Based on the Adafruit Trinket Sound-Reactive LED Color Organ
// http://learn.adafruit.com/trinket-sound-reactive-led-color-organ/code
#define RADAR A5 // RADAR inut is attached to A7
#define MICRODELAY 100 // 100microseconds ~10000hz
#define MAXINDEX 1024 // 10 bits
#define TOPINDEX 1023 // 10 bits
byte collect[MAXINDEX];
int mean;
int minimum;
int maximum;
int hysteresis; // 1/16 of max-min
bool currentphase; // are value above mean + hysteresis;
int lastnull; // index for last null passing value
int prevnull; // index for previous null passing value
int deltaindex;
int deltadeltaindex;
int index;
bool phasechange = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while (!Serial) {}
index = 0;
mean = 0;
maximum = 255;
minimum = 0;
hysteresis = 0;
currentphase = false;
lastnull = 0;
prevnull = 0;
Serial.print("deltadeltaindex");
Serial.print("\t");
Serial.print("deltaindex");
Serial.print("\t");
Serial.println("delta");
}
void loop() {
int newVal = analogRead(RADAR); // Raw reading from amplified radar
mean -= (collect[index] >> 2);
mean += (newVal >> 2);
collect[index]= newVal;
minimum = newVal < minimum ? newVal : minimum + 1;
maximum = newVal > maximum ? newVal : maximum - 1;
hysteresis = abs(maximum - minimum) >> 5;
if(newVal > (mean + hysteresis))
{
if(false == currentphase)
{
currentphase = true;
phasechange = true;
}
}
else if(newVal < (mean - hysteresis))
{
if(currentphase)
{
currentphase = false;
phasechange = true;
}
}
if(phasechange)
{
prevnull = lastnull;
lastnull = index;
int delta = (prevnull > lastnull) ?
(lastnull - prevnull + MAXINDEX) :
(lastnull - prevnull);
deltadeltaindex = abs(deltaindex - delta);
deltaindex = delta;
Serial.print(deltadeltaindex);
Serial.print("\t");
Serial.print(deltaindex);
Serial.print("\t");
Serial.println(delta);
}
index = index == TOPINDEX ? 0 : index + 1;
phasechange = false;
//delayMicroseconds(10);
}
I tried it out on my Arduino with HB100(model with breakout board), and it works just fine.
However, what I really wanted to do was to understand the mechanism behind the code. I read some articles on hysteresis and bit-shifting, but I simply cannot understand why the programmer here used bit-shifting.
What would mean -= (collect[index] >> 2); and mean += (newVal >> 2); do to the values exactly?
Help will be appreciated.

Divided and duplicated frame capture output for ADNS 9800 Arduino

I am trying to interface an ADNS 9800 mouse chip which I took from "Sharkoon SHARK ZONE M50" . The original PCB is still in place.
I am trying to obtain a framecapture, which should be 30 x 30 pixels. I have connected the ADNS 9800 with SPI to an Arduino UNO Rev 3 (i.e. 5V operating voltage). I.e. MISO, MOSI, SCLK, DGND, AGND, NCS. I did not connect any voltage, since I concluded from previous attempts that that did not yield a good frame capture.
The current problem is that I get a frame capture that is divided in 3 parts: square top left (with a good image of the surroundings), square bottom left (which is a duplicate of top left) and a rectangle on the right half of the screen of monotone grey colour (which does change depending on light conditions). See image. I want the full screen to be one image, not the divided mess it is now. Therefore, it may be a question of the resolution that is used, it may be that it is 15x15 instead of 30x30. However I do not know where this is determined/set.
Also, I find it strange that no input voltage seems to be needed to obtain an image from the camera.
See attachments for frame capture and code (arduino + processing).
Frame output
Arduino code
#include
#include
// Registers
#define REG_Product_ID 0x00
#define REG_Revision_ID 0x01
#define REG_Motion 0x02
#define REG_Delta_X_L 0x03
#define REG_Delta_X_H 0x04
#define REG_Delta_Y_L 0x05
#define REG_Delta_Y_H 0x06
#define REG_SQUAL 0x07
#define REG_Pixel_Sum 0x08
#define REG_Maximum_Pixel 0x09
#define REG_Minimum_Pixel 0x0a
#define REG_Shutter_Lower 0x0b
#define REG_Shutter_Upper 0x0c
#define REG_Frame_Period_Lower 0x0d
#define REG_Frame_Period_Upper 0x0e
#define REG_Configuration_I 0x0f
#define REG_Configuration_II 0x10
#define REG_Frame_Capture 0x12
#define REG_SROM_Enable 0x13
#define REG_Run_Downshift 0x14
#define REG_Rest1_Rate 0x15
#define REG_Rest1_Downshift 0x16
#define REG_Rest2_Rate 0x17
#define REG_Rest2_Downshift 0x18
#define REG_Rest3_Rate 0x19
#define REG_Frame_Period_Max_Bound_Lower 0x1a
#define REG_Frame_Period_Max_Bound_Upper 0x1b
#define REG_Frame_Period_Min_Bound_Lower 0x1c
#define REG_Frame_Period_Min_Bound_Upper 0x1d
#define REG_Shutter_Max_Bound_Lower 0x1e
#define REG_Shutter_Max_Bound_Upper 0x1f
#define REG_LASER_CTRL0 0x20
#define REG_Observation 0x24
#define REG_Data_Out_Lower 0x25
#define REG_Data_Out_Upper 0x26
#define REG_SROM_ID 0x2a
#define REG_Lift_Detection_Thr 0x2e
#define REG_Configuration_V 0x2f
#define REG_Configuration_IV 0x39
#define REG_Power_Up_Reset 0x3a
#define REG_Shutdown 0x3b
#define REG_Inverse_Product_ID 0x3f
#define REG_Snap_Angle 0x42
#define REG_Motion_Burst 0x50
#define REG_SROM_Load_Burst 0x62
#define REG_Pixel_Burst 0x64
byte initComplete=0;
byte testctr=0;
unsigned long currTime;
unsigned long timer;
volatile int xdat;
volatile int ydat;
volatile byte movementflag=0;
const int ncs = 10;
const int lsPin = 4;//ANALOG
const int linearActPin = 9;
extern const unsigned short firmware_length;
extern const unsigned char firmware_data[];
String parseChar = ".";
void setup() {
Serial.begin(115200);
//For first parse put LF and CR there
Serial.println("");
//pinMode(ls, INPUT);
//ADNS 9800 setup
pinMode (ncs, OUTPUT);
SPI.begin();
SPI.setDataMode(SPI_MODE3);
SPI.setBitOrder(MSBFIRST);
//Set clock to 2 MHz
SPI.setClockDivider(8);
performStartup();
dispRegisters();
delay(100);
//Pin modes
pinMode(linearActPin, OUTPUT);
Serial.print("Ready");
Serial.println(parseChar);
//Serial.println("Device is ready");
//FrameCapture();
}
/* DO NOT EDIT BELOW; NECESSARY FOR ADNS9800 */
void performStartup(void){
// reset the chip
adns_com_end(); // ensure that the serial port is reset
adns_com_begin(); // ensure that the serial port is reset
adns_com_end(); // ensure that the serial port is reset
adns_write_reg(REG_Power_Up_Reset, 0x5a); // force reset
delay(50); // wait for it to reboot
// read registers 0x02 to 0x06 (and discard the data)
adns_read_reg(REG_Delta_X_L);
adns_read_reg(REG_Delta_X_H);
adns_read_reg(REG_Delta_Y_L);
adns_read_reg(REG_Delta_Y_H);
// upload the firmware
adns_upload_firmware();
delay(10);
//enable laser(bit 0 = 0b), in normal mode (bits 3,2,1 = 000b)
// reading the actual value of the register is important because the real
// default value is different from what is said in the datasheet, and if you
// change the reserved bytes (like by writing 0x00...) it would not work.
byte laser_ctrl0 = adns_read_reg(REG_LASER_CTRL0);
adns_write_reg(REG_LASER_CTRL0, laser_ctrl0 & 0xf1 );
//0x08 = enable fixed framerate, leave rest standard
//0x10 = disable AGC, leave rest standard
adns_write_reg(REG_Configuration_II, 0x08);
//Set resolution; cpi = REG_value x50
//Min: 0x01 50 cpi
//Max: 0xA4 8200 cpi
adns_write_reg(REG_Configuration_I, 0xA4);
//Set fixed framerate: FR = clk_freq/REG_value = 2000 fps
adns_write_reg(REG_Frame_Period_Max_Bound_Lower, 0xa8);
adns_write_reg(REG_Frame_Period_Max_Bound_Upper, 0x61);
//Set shutter time
adns_write_reg(REG_Shutter_Max_Bound_Lower,0x00);
adns_write_reg(REG_Shutter_Max_Bound_Upper,0x08);
//adns_write_reg(REG_Snap_Angle, 0x80);
delay(1);
Serial.print("Initialized");
Serial.println(parseChar);
}
void adns_com_begin(){
digitalWrite(ncs, LOW);
}
void adns_com_end(){
digitalWrite(ncs, HIGH);
}
byte adns_read_reg(byte reg_addr){
adns_com_begin();
// send adress of the register, with MSBit = 0 to indicate it's a read
SPI.transfer(reg_addr & 0x7f );
delayMicroseconds(100); // tSRAD
// read data
byte data = SPI.transfer(0);
delayMicroseconds(1); // tSCLK-NCS for read operation is 120ns
adns_com_end();
delayMicroseconds(19); // tSRW/tSRR (=20us) minus tSCLK-NCS
return data;
}
void adns_write_reg(byte reg_addr, byte data){
adns_com_begin();
//send adress of the register, with MSBit = 1 to indicate it's a write
SPI.transfer(reg_addr | 0x80 );
//sent data
SPI.transfer(data);
delayMicroseconds(20); // tSCLK-NCS for write operation
adns_com_end();
delayMicroseconds(100); // tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound
}
void adns_upload_firmware(){
// send the firmware to the chip, cf p.18 of the datasheet
//Serial.println("Uploading firmware...");
// set the configuration_IV register in 3k firmware mode
adns_write_reg(REG_Configuration_IV, 0x02); // bit 1 = 1 for 3k mode, other bits are reserved
// write 0x1d in SROM_enable reg for initializing
delay(10);
adns_write_reg(REG_SROM_Enable, 0x1d);
// wait for more than one frame period
delay(10); // assume that the frame rate is as low as 100fps... even if it should never be that low
// write 0x18 to SROM_enable to start SROM download
adns_write_reg(REG_SROM_Enable, 0x18);
// write the SROM file (=firmware data)
adns_com_begin();
//write burst destination adress
//bitwise OR to ensure MSB is 1
SPI.transfer(REG_SROM_Load_Burst | 0x80);
delayMicroseconds(50);
// send all bytes of the firmware
unsigned char c;
for(int i = 0; i < firmware_length; i++){
c = (unsigned char)pgm_read_byte(firmware_data + i);
SPI.transfer(c);
delayMicroseconds(15);
}
adns_com_end();
}
void adns_frame_capture(){
//Send signal to start datacollection frame capture
Serial.print("Frame capture");
Serial.println(parseChar);
// reset the chip
adns_write_reg(REG_Power_Up_Reset, 0x5a); // force reset
delay(50); // wait for it to reboot
delay(10);
//Write bytes to Frame_Capture
adns_write_reg(REG_Frame_Capture, 0x93);
adns_write_reg(REG_Frame_Capture, 0xc5);
// wait for more than two frame periods
delay(25); // assume that the frame rate is as low as 100fps... even if it should never be that low
//Check for the first pixel bij reading bit zero of Motion register
//If it is 1, first pixel available
byte motion = adns_read_reg(REG_Motion);
adns_com_begin();
delayMicroseconds(120);//delay t-SRAD = 100 us
byte pixel_burst;
if (motion == 0x21){
//Reading pixel values from ADNS and storing them in Array
for(int i = 0; i < 900; i++){
pixel_burst = adns_read_reg(REG_Pixel_Burst);
//Serial.print(i);
//Serial.print(":");
Serial.print(String(pixel_burst));
Serial.println(parseChar);
delayMicroseconds(15);
}
//Finished transmitting data
Serial.print("Data transfer finished");
Serial.println(parseChar);
//Transfer surface quality value
Serial.print("SQUAL");
Serial.print(String(adns_read_reg(REG_SQUAL)));
Serial.println(parseChar);
}else {
Serial.print("Frame capture failed");
Serial.println(parseChar);
}
adns_com_end();
//Hardware reset and firmware restore required to return navigation
performStartup();
}
void dispRegisters(void){
int oreg[7] = {
0x00,0x3F,0x2A,0x02 };
char* oregname[] = {
"Product_ID","Inverse_Product_ID","SROM_Version","Motion" };
byte regres;
digitalWrite(ncs,LOW);
int rctr=0;
for(rctr=0; rctr<4; rctr++){
SPI.transfer(oreg[rctr]);
delay(1);
//Serial.println("---");
//Serial.println(oregname[rctr]);
//Serial.println(oreg[rctr],HEX);
regres = SPI.transfer(0);
//Serial.println(regres,BIN);
//Serial.println(regres,HEX);
delay(1);
}
digitalWrite(ncs,HIGH);
}
/*********************************************************
DO NOT EDIT ABOVE; NECESSARY FOR RUNNING ADNS9800
*********************************************************/
String data = String();
//Process variables
int run = 0;
int t = 0;
unsigned long t_ms, t_us;
int dt = 0;//1/f = [ms]
long int t_run = 0;//[ms]
unsigned long ms_start, us_start;
void loop() {
if (dt == -1 || t_run == -1){
Serial.print("Time constant error");
Serial.println(parseChar);
}else if (run == 1 && t<t_run){
measure();
Serial.print(data);
Serial.println("");
Serial.println(parseChar);
}else if(run == 1 && t>=t_run){
//Measurement finished
Serial.print("Measurement finished");
Serial.println(parseChar);
digitalWrite(linearActPin, LOW);
run = 0;
t = 0;
}
}
void serialEvent(){
String data_rx;
if (Serial.available() > 0){
//Parse serial data until '.'
data_rx = Serial.readStringUntil('.');
//Remove '.' from buffer
data_rx = data_rx.substring(0, data_rx.length());
//Serial.print(data_rx);
if (data_rx.equals("Run")){
run = 1;
ms_start = millis();
us_start = micros();
digitalWrite(linearActPin, HIGH);
//Read registers and discard data
byte XDataL = adns_read_reg(REG_Delta_X_L);
byte XDataH = adns_read_reg(REG_Delta_X_H);
byte YDataL = adns_read_reg(REG_Delta_Y_L);
byte YDataH = adns_read_reg(REG_Delta_Y_H);
}else if(data_rx.equals("Frame capture run")){
adns_frame_capture();
}else if(data_rx.equals("SQUAL")){
Serial.println(String(adns_read_reg(REG_SQUAL)));
}else if(data_rx.startsWith("dt")){
dt = data_rx.substring(2,data_rx.length()).toInt();
}else if(data_rx.startsWith("trun")){
t_run = data_rx.substring(4,data_rx.length()).toInt();
}
}
}
void measure(void){
/*READ dx, dy, ls
increment t with dt
return String "t,dx,dy,ls"*/
//Read optic flow from ADNS
byte XDataL = adns_read_reg(REG_Delta_X_L);
byte XDataH = adns_read_reg(REG_Delta_X_H);
byte YDataL = adns_read_reg(REG_Delta_Y_L);
byte YDataH = adns_read_reg(REG_Delta_Y_H);
int ls;
unsigned long us, ms;
xdat = int(XDataH<<8);
ydat = int(YDataH<<8);
xdat |=int(XDataL);
ydat |=int(YDataL);
//int between 0-1023, with 5V/1024 = 0.0049 V/unit
ls = analogRead(lsPin);
//Calculate time elapsed between measurements
ms = millis();
us = micros();
t_ms = ms-ms_start;
t_us = us-us_start;
t = t_ms;
//Convert datatypes to string objects and combine
//us can always be divided by 4, so accurate to a resolution of 4 us
String d1 = String(t_ms);
String d2 = String(t_us);
String d3 = String(xdat);
String d4 = String(ydat);
String d5 = String(ls);
data = d2+","+d3+","+d4+","+d5;
//Increment time
delay(dt);
}
Processing code
/* BEP experiment
Communicates with arduino to conduct experiment
Receives and stores data
/
/ DATA PROTOCOL
data_rx
R start measuring
S do screendump
D device is ready
F measurement finished
/
import processing.serial.;
import controlP5.*;
//Serial COMM
Serial arduino;
String data_rx, data_tx;
String parseChar = ".";
//GUI
ControlP5 cp5;
Textfield txtfldDistance, txtfldSpeed, txtfldTs, txtfldN,
txtfldFl, txtfldBron, txtfldPattern, txtfldTrun;
Button btnRun, btnStop, btnFrame;
//File I/O
PrintWriter writer;
String path;
//Runtime variables
int run = 0;
int createWriter = 0;
int frameCapture = 0;
int frameDisplay = 0;
//Time management
String timestamp;
int ms, ms_start;
final int frameX = 30;
final int frameY = 30;
void setup() {
frameRate(60);
time();
//Create GUI
textSize(20);
size(360,660);
//Create textboxes
cp5 = new ControlP5(this);
txtfldDistance = cp5.addTextfield("Distance[m]:")
.setPosition(30, 30)
.setSize(70, 30)
.setAutoClear(false)
.setText("0.5");
txtfldSpeed = cp5.addTextfield("Speed[rev/s]:")
.setPosition(30, 90)
.setSize(70, 30)
.setAutoClear(false);
txtfldTs = cp5.addTextfield("t_s[ms]")
.setPosition(30, 150)
.setSize(70, 30)
.setAutoClear(false)
.setText("10");
txtfldTrun = cp5.addTextfield("t_run[s]")
.setPosition(30, 210)
.setSize(70, 30)
.setAutoClear(false);
txtfldFl = cp5.addTextfield("f[mm]")
.setPosition(130, 30)
.setSize(70, 30)
.setAutoClear(false)
.setText("14");
txtfldBron = cp5.addTextfield("Bron[Watt]")
.setPosition(130, 90)
.setSize(70, 30)
.setAutoClear(false)
.setText("40");
txtfldPattern = cp5.addTextfield("Pattern[mm]")
.setPosition(130, 150)
.setSize(70, 30)
.setAutoClear(false)
.setText("random");
txtfldN = cp5.addTextfield("n")
.setPosition(130, 210)
.setSize(70, 30)
.setAutoClear(false)
.setText("1");
btnRun = cp5.addButton("Run")
.setPosition(230, 270)
.setSize(50,30)
.lock();
btnStop = cp5.addButton("Stop")
.setPosition(150, 270)
.setSize(50,30)
.lock();
btnFrame = cp5.addButton("Frame_Capture")
.setPosition(30, 270)
.setSize(90,30)
.lock();
//Create Serial COMM object
print(timestamp+"SERIAL PORT: ");
println(Serial.list());
// List all the available serial ports:
//arduino = new Serial(this, Serial.list()[2], 115200);
arduino = new Serial(this, Serial.list()[0], 115200);
arduino.clear();
arduino.bufferUntil('.');
}
void draw() {
time();
Frame_Capture();
display_frame();
if (frameDisplay == 1){
display_frame();
frameDisplay = 0;
println(timestamp+"---------------------");
}
}
int n = 0;
int[] frame_capture_data = new int[900];
void serialEvent(Serial arduino){
if (arduino.available() > 0){
//Parse serial data until '.'
data_rx = arduino.readStringUntil('.');
//Remove CR, LF and '.' from buffer
data_rx = data_rx.substring(2, data_rx.length()-1);
//print(n+":");
//println(data_rx);
if(data_rx.equals("Data transfer finished")){
println(timestamp+"Data transfer finished.");
println(timestamp+"Generating visual.");
frameCapture = 0;
frameDisplay = 1;
n = 0;
//unlock textfields
txtfldSpeed.unlock();
txtfldDistance.unlock();
txtfldTs.unlock();
txtfldBron.unlock();
txtfldPattern.unlock();
txtfldFl.unlock();
txtfldN.unlock();
btnRun.unlock();
btnStop.unlock();
btnFrame.unlock();
}else if(data_rx.equals("Ready")){
println(timestamp+"Device is ready.");
println(timestamp+"---------------------");
//unlock textfields
btnRun.unlock();
btnStop.unlock();
btnFrame.unlock();
}else if(data_rx.equals("Initialized")){
println(timestamp+"Device is initialized.");
}else if(data_rx.equals("Measurement finished")){
println(timestamp+"Measurement completed.");
Stop();
}else if(data_rx.equals("Frame capture")){
println(timestamp+"Frame capture transfer started.");
frameCapture = 1;
}else if(data_rx.equals("Frame capture failed")){
println(timestamp+"Frame capture failed. Try again.");
println(timestamp+"---------------------");
//unlock textfields
txtfldSpeed.unlock();
txtfldDistance.unlock();
txtfldTs.unlock();
txtfldBron.unlock();
txtfldPattern.unlock();
txtfldFl.unlock();
txtfldN.unlock();
btnRun.unlock();
btnStop.unlock();
btnFrame.unlock();
}else if(data_rx.contains("SQUAL")){
print(timestamp+"SQUAL: ");
println(data_rx.substring(5,data_rx.length()));
}else if(data_rx.equals("Time constant error")){
print(timestamp+"TIME CONSTANT ERROR");
}else if(frameCapture == 1 && n < 900){
frame_capture_data[n] = int(data_rx);
n++;
}else if(run == 1){
//print(data_rx);
writer.print(data_rx);
}
}
}
public void Run() {
/* When RUN is pressed program starts to run */
//Read value to determine path
float speed = float(txtfldSpeed.getText());
float distance = float(txtfldDistance.getText());
int t_s = int(txtfldTs.getText());
int bron = int(txtfldBron.getText());
int fl = int(txtfldFl.getText());
String pattern = txtfldPattern.getText();
String date = day()+"-"+month();
int n = int(txtfldN.getText());
// Create CSV data file, showing the results from experiment
if (speed > 0 && distance > 0){
if (createWriter == 0){
//Creating objects for writing to file
path = "data/"+date+"/x="+distance+"/"+"x="+distance+"_v="+speed+
"_ts="+t_s+"_f="+fl+"_bron="+bron+"_pat="+pattern+"_n="+n+".csv";
writer = createWriter(path);
//Runtime variables
createWriter = 1;
run = 1;
ms_start = millis();
//Transmit t_s en t_run
arduino.write("dt"+txtfldTs.getText());
arduino.write(parseChar);
arduino.write("trun"+int(txtfldTrun.getText())*1000);
arduino.write(parseChar);
//Transmit starting char to arduino
arduino.write("Run");
arduino.write(parseChar);
//Header
//writer.println("t_ard_ms,t_ard_us,dx,dy,ls");
//lock textfields
txtfldSpeed.lock();
txtfldDistance.lock();
txtfldTs.lock();
txtfldBron.lock();
txtfldPattern.lock();
txtfldFl.lock();
txtfldN.lock();
btnRun.lock();
btnStop.lock();
btnFrame.lock();
println(timestamp+"PROGRAM INITIATED");
println(timestamp+"File stored at: "+path);
}
//ERROR messages
} else if (speed <= 0 && distance <= 0){
println(timestamp+"ERROR: INVALID SPEED AND DISTANCE");
} else if (speed <= 0){
println(timestamp+"ERROR: INVALID SPEED");
} else if (distance <= 0){
println(timestamp+"ERROR: INVALID DISTANCE ");
} else if(txtfldSpeed.getText().equals("")){
println(timestamp+"ERROR: Enter paramaters.");
}
}
public void Stop() {
/* When STOP is pressed program terminates and writes to file */
if (createWriter == 1){
//Write to file and close stream
writer.flush();
writer.close();
//Runtime variables
run = 0;
createWriter = 0;
//unlock textfields
txtfldSpeed.unlock();
txtfldDistance.unlock();
txtfldTs.unlock();
txtfldBron.unlock();
txtfldPattern.unlock();
txtfldFl.unlock();
txtfldN.unlock();
btnRun.unlock();
btnStop.unlock();
btnFrame.unlock();
txtfldN.setText(str(int(txtfldN.getText())+1));
if (int(txtfldN.getText()) > 5){
txtfldN.setText("1");
txtfldSpeed.clear();
}
println(timestamp+"Data written to file.");
println(timestamp+"---------------------");
}
}
public void Frame_Capture() {
arduino.write("Frame capture run");
arduino.write(parseChar);
//lock textfields
txtfldSpeed.lock();
txtfldDistance.lock();
txtfldTs.lock();
txtfldBron.lock();
txtfldPattern.lock();
txtfldFl.lock();
txtfldN.lock();
btnRun.lock();
btnStop.lock();
btnFrame.lock();
}
void display_frame(){
int[] frame1 = new int[225];
int[] frame2 = new int[255];
int x = 30;
int y = 320;
//resolutie 10x10
int s = 10; // size of pixel, i.e. side lengths
//Max res is 30x30
int sz = 10;
int res = 30;
for (int i = 0; i < 15; i++){
for (int m = 0; m < 15; m++){
frame1[15*i+m] = frame_capture_data[30*i+m];
frame2[15*i+m] = frame_capture_data[30*i+m+15];
}
}
//for (int i = 0; i < res*res; i++){
//Commented by Daan:
//for (int j = 0; j < res; j++){ // j resembles the column index.
// for (int k = 0; k < res; k++){ // k resembles the row index
// //fill(map(frame_capture_data[30*j+k],0,63,0,255));
// //frame_capture_data[30*j+k] = 300; // test to see how the pixel values can be manipulated
// fill(float(frame_capture_data[30*j+k]));
// rect(x+j*10, y+300-k*10, s, s);
// //println(frame_capture_data[30*j+k]);
// }
//}
for( int i = 0; i < 900; i++ )
{
fill( map(frame_capture_data[i], 0, 63, 0, 255) ); // Convert from ADNS greyscale to 0 - 255 grey scale format.
rect(x + (i / frameX * sz), // Each rect() is a rectangle that represents a pixel. I.e. width and height of each pixel is "sz".
y +300 - (i % frameY * sz),
sz, sz);
// //rect(off_x + (i % frameX * sz), // Each rect() is a rectangle that represents a pixel. I.e. width and height of each pixel is "sz".
// //off_y + (i / frameY * sz),
// //sz, sz);
}
fill(255,0,0);
rect(x+3*10, y+300-8*10, s, s); // this is red test dot, j = 3 (column), k = 8 (row).
// I.e. this is the 30*3 + 8 = 98 th pixel in frame stream from sensor.
}
public void time(){
/* Keeps track of time
Creates timestamp for messages*/
String h = str(hour());
String m = str(minute());
String s = str(second());
if (int(h) < 10){
h = "0"+h;
} else if(int(m) < 10){
m = "0"+m;
} else if(int(s) < 10){
s = "0"+s;
}
timestamp = "["+h+":"+m+":"+s+"] ";
}

How to measure the time of transferring a file from the server to the client?

I want to measure the time of transferring a file from the send to the recv by the PGM/UDP protocol. Actually , I try to use clock() function to measure the execution time of both the send and recv program ,but it seems to be incorrect. What should I do to measure the time of transferring a file ?
Here is the code :
clock_t t = clock();
do
{
struct timeval tv;
size_t len;
int timeout;
pgm_error_t *pgm_err = NULL;
const int status = pgm_recv (rx_sock,
buf,
sizeof(buf),
0,
&len,
&pgm_err);
switch (status)
{
case PGM_IO_STATUS_NORMAL:
/* receive file */
if (len < 30)
{
strncpy(newFile, buf, len);
if (0 == strncmp(newFile, testNewFile, len))
{
flag = 1;
continue;
}
strncpy(endFile, buf, len);
if (0 == strncmp(endFile, testEndFile, len))
{
//g_quit = 1;
t = clock() -t;
printf("%s takes time: %f\n", fileName, ((float)t) / CLOCKS_PER_SEC);
continue;
}
}
if (flag == 1)
{
strncpy(fileName, buf, len);
// puts(fileName);
fp = fopen(fileName, "wb");
g_assert(fp);
flag = 0;
}
else
num_read = fwrite (buf, sizeof(char), len, fp);
break;
case PGM_IO_STATUS_TIMER_PENDING:
{
socklen_t optlen = sizeof (tv);
pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_TIME_REMAIN, &tv, &optlen);
}
goto block;
case PGM_IO_STATUS_RATE_LIMITED:
{
socklen_t optlen = sizeof (tv);
pgm_getsockopt (rx_sock, IPPROTO_PGM, PGM_RATE_REMAIN, &tv, &optlen);
}
case PGM_IO_STATUS_WOULD_BLOCK:
block:
timeout = PGM_IO_STATUS_WOULD_BLOCK == status ? -1 : ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
memset (fds, 0, sizeof(fds));
fds[0].fd = g_quit_pipe[0];
fds[0].events = POLLIN;
pgm_poll_info (rx_sock, &fds[1], &n_fds, POLLIN);
poll (fds, 1 + n_fds, timeout);
break;
default:
if (pgm_err)
{
g_warning ("%s", pgm_err->message);
pgm_error_free (pgm_err);
pgm_err = NULL;
}
if (PGM_IO_STATUS_ERROR == status)
break;
}
}while (!g_quit);
fclose (fp);
return NULL;

Resources