Is there a way to pass which "level" of structure is desired to a formula in (Arduino) C++? - c++

I am not hugely experienced in C++ coding, but I learn pretty well as I go. But, I have not been able to properly query how to do this, may be using wrong terms or insufficiently expressing my desire. Here's the situation.
I have a lot of variables (3x12) that I have set up under a structure:
struct Tracking
{
String Title;
BoolArray n24hr;
bool State;
unsigned char Days, Weeks;
uint16_t Minutes, TotalMinutes, Daily, Weekly, Monthly, n7d[7], n4w[4];
} Components[3];
I also have code that performs basically the same thing 3 times but on different "levels", e.g. daily, weekly, monthly. It keeps tracks of status over those time periods, filling arrays, finding totals, and duty cycles, etc. It fills the minutes into days, and when that reaches a week, it puts the totals into a week format, and repeats until it reaches monthly levels. So basically, I have it doing something like:
in my main loop:
//calls status formula
StatusFormula();
in a separate file:
//status formula defined
void StatusFormula()
{
// for each element of Components:
//determine current status
//for daily
//add it to the correct spot in the array
//perform calculations on it
//when it reaches a week:
//add it to the correct spot in the next array
//perform calculations on it
//when it reaches a month:
//add it to the correct spot in the next array
//perform calculations on it
}
These calculations are all basically the same, the only differences are the structure member names & the constants for the calculations (i.e., MinsADay, DaysAWk, etc.).
I can get it to work this way, it just means a lot more lines and if I want to change something, I have to repeat it 3 times. What I want is something like this:
in my main loop:
//calls status formula
StatusFormula("Daily"); //sends the status formula information to decide which level (daily, weekly, monthly), it supposed to work on
if (Components[i].Minutes == MinsADay)
{
StatusFormula("Weekly"); //sends the status formula information to decide which level (daily, weekly, monthly), it supposed to work on
if (Components[i].Daily == DaysAWk)
{
StatusFormula("Monthly");
}
}
in a separate file:
//status formula defined
void StatusFormula()
{
//determine which level & variables to use (I would probably use case for this), then
//add it to the correct spot in the correct array
//perform calculations on it
}
I tried passing the level using a string, but it didn't work:
in my main loop:
StatusFormula(i, "Daily"); //sending data to formula, where i is value 0 to 2 for the Components array & defined earlier in the for loop.
in a separate file:
//formula defined as:
void StatusFormula(uint8_t counter, string level)
{Components[counter].level -= //etc... performing calculations as desired.
//so I thought this should evaluate to "Components[i].Daily -=" (& i would be a value 0 to 2) & treat it like the structure, but it doesn't work that way apparently.
I tried passing the structure & variable itself, but that didn't work either:
in my main loop:
StatusFormula(i, Components[i].Daily); //sending data to formula
in a separate file:
//formula defined as:
void StatusFormula(uint8_t counter, Tracking& level)
{level -= //etc... //(level should be Components[i].Daily -=" (& i would be a value 0 to 2)) this didn't work either.
I couldn't find any google searches to help me, and I trialed-and-errored a bunch of ways, but I couldn't figure out how to do that in C++, let alone on the Arduino platform. In Excel VBA, I would just have the variable passed as a string to the formula, which would substitute the word and then treat it like the variable that it is, but I couldn't make that happen in C++. Also to note, I am going to try and define this a separate file/tab so that my massive code file is easier to read/edit, in case that makes a difference. I would paste my code directly, but it is long and super confusing.
I guess what I am asking is how would I pass the structure and/or structure member to the formula in a way that would say the equivalent of:
case 1: //"Daily"
//use Components[i].Daily & Components[i].Minutes & MinsaDay
break;
case 2: //"Weekly"
//use Components[i].Weekly & Components[i].Days & DaysaWk
break;
//etc.
I feel like there should be a way & that I am just missing a small, vital piece. Several people in the comments suggested enums, and after researching, it might possibly be what I want, but I am having trouble visualizing it at the moment and need to do more research and examples. Any suggestions or examples on how to send the appropriate structure & members to the formula to be modified in it?

Related

Storing timepoints or durations

I want to make a simple editor to shift subtitle times around. A Subtitle of WebVTT is made of chunks like this:
1
00:02:15.000 --> 00:02:20.000
- Hello World!
So as you can see there is a time that the subtitle will apear and a time that it dissapears. This time is also can be clicked to jump to that specific point of the video file.
Now I want to create a simple application that can shift these times by a given amount to left or right in time domain. What would be the best way to store these timepoints for making easy calculation and changes?
For example:
struct SubtitleElement {
std::chrono< ?????? > begin; // What is a good candidate here?
std::chrono< ?????? > end; // What is a good candidate here?
std::string text;
}
Later I want to have functions that operate on these elements. E.g.:
void shiftTime(SubtitleElement element, int millisecs) {
// reduce begin and end of the element by millisecs
}
DURATION getDuration(SubtitleElement& element) {
//return end - begin
}
DURATION totalDuration(vector<SubtitleElement> elements) {
// sum all the durations of the elements in vector
}
So what would the most clean and modern way of doing this? Also important is that it will be easy to convert the string "hh:mm:ss:ZZZ" to that member. Please note that I think the hh can be much more than 24, because its amount of time, not time of the day! E.g. a vido file can be 120 hours long!!
Since these are time points relative to the beginning of the video, not to some clock, I suggest keeping it simple and using std::chrono::milliseconds. They support all operations you require, except im not sure there is an existing implementation for parsing them from a string. But that should be very easy to build.

QProcess How to deal with too much input?

I'm using 3 command line tools via QProcesses to play music on my Linux (Mint) desktop via the Jack server. It's all working very well, but the input from one of the tools 'jack_showtime' arrives at about 12,000 lines per second.
I only need to see one line every 0.1 seconds, but the only way I've found to get a full recent line is like:
j_s->readAll(); // j_s is the jack_showtime QProcess
waitAbit(20); // a 20 mS delay
QString aShowtimeLine = j_s->readLine();
aShowtimeLine = j_s->readLine();
What would be a better way to deal with so much unwanted input? It seems that; without the readAll, a line will be much too old. Without the delay, I get a blank line and without the two readLines I get part of a line.
I'd also be interested in a Bash script that could absorb most of the input, or similar.
I suggest something like this, such that no matter how fast or how slow you get input from the child process, you always use the only most recent value, every 100mS:
// at startup or in your class constructor or wherever
connect(j_s, SIGNAL(readyRead()), this, SLOT(ReadDataFromJack()));
connect(&_myQTimer, SIGNAL(timeout()), this, SLOT(UseOneLine()));
_myQTimer.start(100);
void MyClass :: ReadDataFromJack()
{
while(j_s->canReadLine())
{
char buf[1024];
qint64 bytesRead = j_s->readLine(buf, sizeof(buf));
if ((bytes > 0)&&(CanParseText(buf))
{
this->_mostRecentResult = ParseText(buf);
}
}
}
void MyClass :: UseOneLine()
{
printf("100mS have elapsed, time to use _mostRecentResult=%i for something!\n", this->_mostRecentResult)
}
(Note that CanParseText(buf) and ParseText(buf) above are imaginary placeholders for whatever code you use to parse ASCII text coming from your child process into data to be used by your program)
Bulls eye! Thank you. You seem to know what I already had, so it was easy to add the bits I didn't have. Mainly the limited size buffer and, as I've never seen a line longer than 79 characters, I reduced it to 100. I may have been on the right track, while looking for a script solution, when I tried to use 'stdbuf', but dealing with it all in my program is much better.
Lines received are easy to parse. I only want the first number (which can be as low as zero) from something like this:
frame = 293532731 frame_time = 114978548 usecs = 2421437949 state: Rolling
I use the following, which seems reasonably minimal:
QString recentLine = QString::fromLocal8Bit(buf);
recentLine.remove(0,8);
recentLine.chop(recentLine.length() - recentLine.indexOf(" "));
int numSamples = recentLine.toInt();
I put a counter in the ReadDataFromJack() class and see between 2,000 and 3,000 visits per 100mS!
The number represents the position of the 'play head' in samples (at 48k per second) and wont exceed the integer range in Qt, but I see you use a qint64 (long long) in your example. Should I do the same for my number?
Sorry it's an answer (and a further question), but it's too long for a comment.

Change variable value of the already running program

I think it is impossible, but I should try.
I have a program, that is doing a physical simulation and recording frames to files. It is recording until the breakup value is not achieved, like:
int counter=0; //global variable
void SomeFunction()
{
...
if(counter == 400) //written exactly by this way, i.e. 400 is not a variable, just a number
PostQuitMessage(0);
else
MakeScreenshot();
counter++;
...
}
The problem is that I forgot to change if(counter == 400) to if(counter == 1000) and now program will be finished with 400 frames, although I need exactly 1000.
I can’t just recompile the program because calculations are very heavy and the program is already running for 2 days, I can’t wait.
It is very important for me, is there any way to change the if statement, or exactly the variable value during the program running?
The only hope I have, is, as far as I remember there was programs that could like change money/health/another stuff in games, and there user exactly could search a variable by value, and change it
Currently it is on about 200-300 frame, I have so little time to fix it.
You can use the Windows functions ReadProcessMemory and WriteProcessMemory.
But you need to determine the position of the value 400. Looking for the value in the running program can be done with the above functions. Depending on the size of the constant, it should be either a USHORT or an UINT.
So you can use the following steps:
Look for the value in a second instance
Isolate the surrounding OpCode sequence.
For example, a cmp xxx, 400
Look for this OpCode sequence in the running executable to find the unique location and replace the crucial value by 1000.
This can be called "hot-patch". It's how simple in-memory cheats do work and requires root privileges.
I downloaded Cheat engine and found address of the counter variable by its value. Through all addresses, the address I need was colored in green.
I changed the value stored at that address to 401, and now all is ok.

c++ Variable values not updated correctly on GUI

I am debugging some simulation software that has been written partly in C++ and partly in Ada. On the GUI, there are two values displaying the ETA & TimeToGo of an entity moving in the simulation on any given leg of its journey, and for the remainder of the whole journey. The TimeToGo & ETA values that are displayed for the current leg are correct (i.e. how long it will take the entity to reach its current target destination from its current location). However, the TimeToGo & ETA values for the remainder of the whole journey are incorrect- approximately 40-50s lagging behind.
I have come across a couple of assignments in the code, and I am wondering if they are the wrong way round:
if(some condition){
mFlightPlanData[0] = fpMiniToteData;
} else {
mFlightPlanData[1] = fpMiniToteData;
}
mFlightPlanData[] is an array of flightPlans, of size 2- because each aircraft can have up to two flight plans at any one time- a primary and a secondary. fpMiniToteData is the variable used to display the flight plan data on the GUI.
Now, it appears to me that these assignments are the wrong way round- these seem to be saying:
Set the first element in the flight plan array equal to the value of the display data
else
Set the second element in the flight plan array equal to the value of the display data
However, what should be happening is that the display data should be being set to the value of either the first or second element in the flight plan array...
I tried to do this, by switching the assignments around, i.e.
if(some condition){
fpMiniToteData = mFlightPlanData[0];
} else {
fpMiniToteData = mFlightPlanData[1];
}
But I now get a compile error that says:
error C2678: binary '=': no operator found which takes a left-hand operand of type 'const...' or there is no acceptable conversion)
What does this error mean? Do I need to have defined a function that will convert the data type held in the array to the data type of the fpMiniToteData?
Any help would be much appreciated.
Edit 12/02/2015 # 1645
fpMiniToteData is defined in the function definition- the function that the code above belongs to:
void FlightPlanInterface::setFlightPlanData(
const FlightPlanMinitoteTypes::FlightPlanPerformanceDataViewId_Type viewId,
const FlightPlanMinitoteTypes::FlightPlanMinitoteData_Variant& fpMiniToteData)
{
and mFlightPlanData is defined in a header file as follows:
private:
FlightPlanMinitoteTypes::FlightPlanMinitoteData_Variant mFlightPlanData[2];

WxTextCtrl unable to load large texts

I've read about the solutuon written here on a post a year ago
wx.TextCtrl.LoadFile()
Now I have a windows application that will generate color frequency statistics that are saved in 3D arrays. Here is a part of my code as you will see on the code below the printing of the statistics is dependent on a slider which specifies the threshold.
void Project1Frm::WxButton2Click(wxCommandEvent& event)
{
char stat[32] ="";
int ***report = pGLCanvas->GetPixel();
float max = pGLCanvas->GetMaxval();
float dist = WxSlider5->GetValue();
WxRichTextCtrl1->Clear();
WxRichTextCtrl1->SetMaxLength(100);
if(dist>0)
{
WxRichTextCtrl1->AppendText(wxT("Statistics\nR\tG\tB\t\n"));
for(int m=0; m<256; m++){
for(int n=0; n<256; n++){
for(int o=0; o<256; o++){
if((report[m][n][o]/max)>=(dist/100.0))
{
sprintf(stat,"%d\t%d\t%d\t%3.6f%%\n",m,n,o,report[m][n][o]/max*100.0);
WxRichTextCtrl1->AppendText(wxT(stat));
}
}
}
}
}
else if(dist==0) WxRichTextCtrl1->LoadFile("histodata.txt");
}
The solution I've tried so far is that when I am to print all the statistics I'll get it from a text file rather than going through the 3D array... I would like to ask if the Python implementation of the segmenting can be ported to C++ or are there better ways to deal with this problem. Thank you.
EDIT:
Another reason why I used a text file instead is that I observed that whenever I do sprintf only [with the line WxRichTextCtrl1->AppendText(wxT(stat)); was commented out] the computer starts to slow down.
-Ric
Disclaimer: My answer is more of an alternative than a solution.
I don't believe that there's any situation in which a user of this application is going to find it useful to have a scrolled text window containing ~16 million lines of numbers. It would be impossible to scroll to one specific location in the list that the user might need to see easily. This is all assuming that every single number you output here has some significance to the user of course (you are showing them on the screen for a reason). Providing the user with controls to look up specific, fixed (reasonable) ranges of those numbers would be a better solution, not only in regards to a better user experience, but also in helping to resolve your issue here.
On the other hand, if you still insist on one single window containing all 64 million numbers, you seem to have a very rigid data structure here, which means you can (and should) take advantage of using a virtual grid control (wxGrid), which is intended to work smoothly even with incredibly large data sets like this. The user will likely find this control easier to read and find the section of data they are looking for.