OpenDDS - Create multiple topics from single IDL structure - c++

In my exercise with OpenDDS I would like to create multiple topics from a single IDL structure, is that possible? otherwise please let me know how to do it.
I do it as below, please correct me if it is not the right way to do it.
The sample I use is available at OpenDDS-3.12/examples/DCPS/IntroductionToOpenDDS
The IDL is as follows,
StockQuoter.idl
---------------
module StockQuoter
{
#pragma DCPS_DATA_TYPE "StockQuoter::Quote"
#pragma DCPS_DATA_KEY "StockQuoter::Quote ticker"
struct Quote {
string ticker;
string exchange;
string full_name;
double value;
string data;
TimeBase::TimeT timestamp;
};
}
publisher.cpp
// Create TOPICS and TYPES Vector
std::stringstream ss;
for(unsigned int idx = 0; idx < 100; ++idx)
{
ss << (idx+1);
TOPICS.push_back("TOPIC" + std::string(ss.str()));
TYPES.push_back("TYPE" + std::string(ss.str()));
ss.clear();
ss.str(std::string());
}
// Register
for( unsigned int idx = 0; idx < 100; ++idx )
{
vec_quote_servent.push_back(new StockQuoter::QuoteTypeSupportImpl());
if (DDS::RETCODE_OK != vec_quote_servent[idx]->register_type(participant.in (), TYPES[idx].c_str()))
{
cerr << "register_type for " << TYPES[idx] << " failed." << endl;
ACE_OS::exit(1);
}
}
// Create a topics
for( unsigned int idx = 0; idx < 100; ++idx )
{
vec_quote_topic.push_back( participant->create_topic (TOPICS[idx].c_str(),
TYPES[idx].c_str(),
default_topic_qos,
DDS::TopicListener::_nil(),
::OpenDDS::DCPS::DEFAULT_STATUS_MASK));
if (CORBA::is_nil (vec_quote_topic[idx].in ())) {
cerr << "create_topic for " << TOPICS[idx] << " failed." << endl;
ACE_OS::exit(1);
}
}
// Create DataWriters
for( unsigned int idx = 0; idx < 100; ++idx )
{
vec_quote_base_dw.push_back( pub->create_datawriter(vec_quote_topic[idx].in (),
dw_default_qos,
DDS::DataWriterListener::_nil(),
::OpenDDS::DCPS::DEFAULT_STATUS_MASK) );
if (CORBA::is_nil (vec_quote_base_dw[idx].in ())) {
cerr << "create_datawriter for " << TOPICS[idx] << " failed." << endl;
ACE_OS::exit(1);
}
vec_quote_dw.push_back( StockQuoter::QuoteDataWriter::_narrow(vec_quote_base_dw[idx].in()) );
if (CORBA::is_nil (vec_quote_dw[idx].in ())) {
cerr << TOPICS[idx] << " could not be narrowed"<< endl;
ACE_OS::exit(1);
}
}
// Create handle
for( unsigned int idx = 0; idx < 100 ; ++idx )
{
{
StockQuoter::Quote topic2;
topic2.ticker = CORBA::string_dup(TOPICS[idx].c_str());
vec_topic_handle.push_back(vec_quote_dw[idx]->register_instance(topic2));
}
}
// Publish data
StockQuoter::Quote vec_quote;
vec_quote.exchange = STOCK_EXCHANGE_NAME;
vec_quote.ticker = CORBA::string_dup("VEC_TOPIC");
vec_quote.full_name = CORBA::string_dup("TOPIC Receipts");
vec_quote.value = 1600.0 + 10.0*i;
vec_quote.timestamp = get_timestamp();
for(unsigned int idx = 0; idx < 100; ++idx )
{
vec_quote.value += idx + 10;
cout << "Publishing " << TOPICS[idx] << " : " << vec_quote.value <<endl;
ret = vec_quote_dw[idx]->write(vec_quote, vec_topic_handle[idx]);
if (ret != DDS::RETCODE_OK) {
ACE_ERROR ((LM_ERROR, ACE_TEXT("(%P|%t) ERROR: TOPIC2 write returned %d.\n"), ret));
}
}

a, now I get the point you wanted to ask. you can define different topic types either in one file per topic, or all in one file. If you define more than one topic type in an IDL file, type support is generated for each file. Let me describe this more precisely with the same example you used. The IDL file for the IntroductionToOpenDDS example looks as follows:
#include "orbsvcs/TimeBase.idl"
module StockQuoter
{
#pragma DCPS_DATA_TYPE "StockQuoter::Quote"
#pragma DCPS_DATA_KEY "StockQuoter::Quote ticker"
struct Quote {
string ticker;
string exchange;
string full_name;
double value;
TimeBase::TimeT timestamp;
};
#pragma DCPS_DATA_TYPE "StockQuoter::ExchangeEvent"
#pragma DCPS_DATA_KEY "StockQuoter::ExchangeEvent exchange"
enum ExchangeEventType { TRADING_OPENED,
TRADING_CLOSED,
TRADING_SUSPENDED,
TRADING_RESUMED };
struct ExchangeEvent {
string exchange;
ExchangeEventType event;
TimeBase::TimeT timestamp;
};
};
As you can see, two types are defined: Quote and ExchangeEvent. When this IDL file gets compiled, type support for both Quote and ExchangeEvent is generated.
You already used the type support for using this line (QuoteTypeSupportImpl):
vec_quote_servent.push_back(new StockQuoter::QuoteTypeSupportImpl());
The same type support is generated for ExchangeEvent, you will find a type support called StockQuoter::ExchangeEvent with a StockQuoter::ExchangeEventTypeSupportImpl() method. Simply use this to create a topic of type ExchangeEvent.
I hope this helps. If more details are needed, feel free to ask.

you can create as many topics as you wish from a single IDL file. you are already doing it with this line:
participant->create_topic (TOPICS[idx].c_str(),
TYPES[idx].c_str(),
default_topic_qos,
DDS::TopicListener::_nil(),
::OpenDDS::DCPS::DEFAULT_STATUS_MASK);
however, each topic you created has the same type. you can also create different types for topics if you have to.

Related

Return struct element from vector c++

I'm new to C++ and I'm trying to return a struct from a vector of structs by using 2 search criteria.
The function find_city is returning me everything from the defined range, regardless of whether it exists inside the vector of struct.
Here's my code:
struct cityLoc
{
int hRange;
int vRange;
int cityCode;
string cityName;
};
vector<cityLoc> cl1;
// the vector has already been preloaded with data
// function to return my struct from the vector
cityLoc find_city(int hRange, int vRange)
{
for (size_t i = 0; i < cl1.size(); i++)
{
if ((cl1[i].hRange = hRange) && (cl1[i].vRange = vRange))
{
return cl1[i];
}
}
}
int main()
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j <= 8; j++)
{
cityLoc this_city;
this_city = find_city(i, j);
cout << this_city.hRange << ", " << this_city.vRange << endl;
}
}
return 0;
}
Also, aside from this question, I was previously looking into std::find_if and didn't understand it. If I have the following code, what is the output? How do I modify it such that it returns a struct?
auto it = find_if(cl1.begin(), cl1.end(), [](cityLoc& cl) { return cl.hRange == 1; } );
You have a bug here:
if ((cl1[i].hRange = hRange) && (cl1[i].vRange = vRange))
Those = are assignments, not comparisons! Please enable compiler warnings and you won't be hurt by such obvious typos in future.
std::find_if will return the iterator to the found struct entry if it is successful, std::vector::end() otherwise. So, you should first validate the returning iterator if it is valid or not.
For example:
auto it = std::find_if( cl1.begin(), cl1.end(),
[](const cityLoc& cl) { return cl.hRange == 1; } );
if ( it == cl1.end() )
{
// ERROR: Not found! Return error code etc.
return -1;
}
// And, if found, process it here...
std::cout << it->hRange << '\n';
std::cout << it->vRange << '\n';
The criteria (predicate) part in std::find_if is a lambda expression.

C++ Calculating Shortest Path in a Directed Graph

I am tasked with writing a program to maintain the representation of a simple network(weighted directed graph) and compute the best path between two given nodes upon request.
Currently, I am attempting to write a function to compute the simplest between two nodes, however, when attempting to run my program, I get two specific error
Severity Code Description Project File Line Suppression State
Error C3863 array type 'bool [openNode]' is not assignable P 127
and
Severity Code Description Project File Line Suppression State
Error C3863 array type 'int [openNode]' is not assignable
I am unable to debug since these two primary errors are not allowing my program to run. Is there any particular reason for these errors?
Thanks in advance!
This is the node structure defined in Graph.h
struct GraphNode
{
char ID;
std::string name;
int inNodes = 0;
int outNodes = 0;
std::vector<std::pair<GraphNode*, int>> connection;
int connections = 0;
};
And here is the particular code that causes the errors.
#include "Graph.h"
std::vector<GraphNode*> _graph;
int openNode = 0;
//Obligatory constructor
void Graph()
{
}
void shortestPath(char fromNode, char toNode)
{
bool known[openNode];
int distance[openNode];
GraphNode* previous[openNode];
int numbChecked = 0;
for (int i = 0; i < openNode; i++)
{
known[i] = false;
distance[i] = 999999;
previous[i] = nullptr;
}
distance[findNode(fromNode)] = 0;
while (numbChecked < openNode)
{
int smallestUnknown = 9999999;
int locationOfSmall = 0;
for (int i = 0; i < openNode; i++)
{
if (known[i] == false && distance[i] < smallestUnknown)
{
smallestUnknown = distance[i];
locationOfSmall = i;
}
}
if (distance[locationOfSmall] == 0)
{
previous[locationOfSmall] = nullptr;
}
known[locationOfSmall] = true;
numbChecked++;
if (_graph[locationOfSmall]->outNodes > 0)
{
for (int i = 0; i < _graph[locationOfSmall]->outNodes; i++)
{
int newDistanceLocation = findNode(_graph[locationOfSmall]->connection[i].first->ID);
if (known[newDistanceLocation] == false && (distance[locationOfSmall] + _graph[locationOfSmall]->connection[i].second) < distance[newDistanceLocation])
{
distance[newDistanceLocation] = distance[locationOfSmall] + _graph[locationOfSmall]->connection[i].second;
previous[newDistanceLocation] = _graph[locationOfSmall];
}
}
}
}
int destination = findNode(toNode);
std::string output;
std::string charTransfer;
charTransfer = toNode;
output = charTransfer;
while (previous[destination] != nullptr)
{
destination = findNode(previous[destination]->ID);
charTransfer = _graph[destination]->ID;
output = charTransfer + "->" + output;
}
if (_graph[destination]->ID != fromNode)
{
std::cout << "The nodes are not connected." << std::endl;
}
else
{
std::cout << "The path is: " << output << std::endl;
std::cout << "The distance is: " << distance[findNode(toNode)] << std::endl;
}
}
Any change suggestions would be much appreciated!
You have invalid code at the beginning of your shortestPath function:
bool known[openNode];
int distance[openNode];
GraphNode* previous[openNode];
You cannot use variables to create arrays on the stack (which is what you are trying to do there), because the compiler doesn't know the value of openNode at compile time (which is needed to determine the stack size).
Why don't you use a vector, like:
std::vector<bool> known(openNode, false);
std::vector<int> distance(openNode, 999999);
std::vector<GraphNode*> previous(openNode, nullptr);
Using this method makes the for loop below obsolete aswell.

Convert String in to MAC address [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 5 years ago.
Inside the file in SPIFFS, I'm saving information about the mac address in the form "XX:XX:XX:XX:XX:XX".
When I read the file, I need to switch it from STRING to a array of hexadecimal values.
uint8_t* str2mac(char* mac){
uint8_t bytes[6];
int values[6];
int i;
if( 6 == sscanf( mac, "%x:%x:%x:%x:%x:%x%*c",&values[0], &values[1], &values[2],&values[3], &values[4], &values[5] ) ){
/* convert to uint8_t */
for( i = 0; i < 6; ++i )bytes[i] = (uint8_t) values[i];
}else{
/* invalid mac */
}
return bytes;
}
wifi_set_macaddr(STATION_IF, str2mac((char*)readFileSPIFFS("/mac.txt").c_str()));
But I'm wrong in the code somewhere
When i put AA:00:00:00:00:01 in file, my ESP8266 set 29:D5:23:40:00:00
I need help, thank you
You are returning a pointer to a "local" variable, i.e. one which's lifetime ends when the function is finished. Using such a pointer then is UB, which may be, for example, the behaviour you are seeing.
To overcome this, you could pass the array as parameter; then the caller is responsible for memory management.
BTW: you could use format %hhx to read in directly into an 8 bit unsigned data type:
int str2mac(const char* mac, uint8_t* values){
if( 6 == sscanf( mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",&values[0], &values[1], &values[2],&values[3], &values[4], &values[5] ) ){
return 1;
}else{
return 0;
}
}
int main() {
uint8_t values[6] = { 0 };
int success = str2mac("AA:00:00:00:00:01", values);
if (success) {
for (int i=0; i<6; i++) {
printf("%02X:",values[i]);
}
}
}
Your code doesn't seem to be compatible with wifi_set_macaddr (I looked up API documentation). It expects a uint8 pointer to mac address, which means the way you wrote it is not going to work (returning pointer to local variable etc). Here is an example which you should be able to adapt to your purpouse:
#include <iostream>
#include <fstream>
// mock up/print result
bool wifi_set_macaddr(uint8_t index, uint8_t *mac)
{
std::cout << "index: " << (int)index << " mac: ";
for (int i = 0; i < 6; ++i)
std::cout << std::hex << (int)mac[i] << " ";
std::cout << std::endl;
return true;
}
// test file
void writeTestFile()
{
std::ofstream ofs("mac.txt");
if (!(ofs << "AA:00:00:00:00:01" << std::endl))
{
std::cout << "File error" << std::endl;
}
ofs.close();
}
int main()
{
writeTestFile();
uint8_t mac[6];
int i = 0, x;
std::ifstream ifs("mac.txt");
for (; i < 6 && ifs >> std::hex >> x; ++i)
{
mac[i] = static_cast<uint8_t>(x);
ifs.ignore();
}
if (i < 6)
{
std::cout << "File error or invalid MAC address" << std::endl;
return 1;
}
wifi_set_macaddr(0x00, mac);
return 0;
}
http://coliru.stacked-crooked.com/view?id=d387c628e590a467

How to prepare statements and bind parameters in Postgresql for C++

I'm quite new to C++ and know a little bit about pqxx library. What I want to implement is to prepare statements and bind parameters. In PHP I'm used to doing this in such a nice and concise manner:
$s = $db->prepare("SELECT id FROM mytable WHERE id = :id");
$s->bindParam(':id', $id);
$s->execute();
or using tokens:
$data = array();
$data[] = 1;
$data[] = 2;
$s = $db->prepare("SELECT id FROM mytable WHERE id = ? or id = ?");
$s->execute($data);
I tried to fugure out from pqxx documentation how to implement this, but to me documentation looks like a mess and lacks short and simple examples (like I provided above). I hope someone can also provide such simple examples (or of comparable simplicity - without having to write some behemoth code) when dealing with Postgresql in C++.
A simple example. This just prints the number of entries with id value 0.
#include<pqxx/pqxx>
#include<iostream>
int main()
{
std::string name = "name";
int id = 0;
try {
//established connection to data base
pqxx::connection c("dbname=mydb user=keutoi");
pqxx::work w(c);
//statement template
c.prepare("example", "SELECT id FROM mytable WHERE id = $1");
//invocation as in varible binding
pqxx::result r = w.prepared("example")(id).exec();
w.commit();
//result handling for accessing arrays and conversions look at docs
std::cout << r.size() << std::endl;
}
catch(const std::exception &e)
{
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}
The function w.prepared() is a bit convoluted. It's similar to a curried(curry) function in haskell, as in it takes a parameter and returns another function which in turn takes another parameter. That kind of thing.
Documentation says:
How do you pass those parameters? C++ has no good way to let you pass an unlimited, variable number of arguments to a function call, and the compiler does not know how many you are going to pass. There's a trick for that: you can treat the value you get back from prepared as a function, which you call to pass a parameter. What you get back from that call is the same again, so you can call it again to pass another parameter and so on.
Once you've passed all parameters in this way, you invoke the statement with the parameters by calling exec on the invocation
If there are more parameters use $1 $2 and so on in the prepare function.
c.prepare("SELECT id name FROM mytable WHERE id = $1 AND name = $2")
and give the varibles as
w.prepared("example")(dollar1_var)(dollar2_var).exec()
An Example for dynamic preparation
#include<pqxx/pqxx>
#include<iostream>
#include<vector>
//Just give a vector of data you can change the template<int> to any data type
pqxx::prepare::invocation& prep_dynamic(std::vector<int> data, pqxx::prepare::invocation& inv)
{
for(auto data_val : data)
inv(data_val);
return inv;
}
int main()
{
std::string name = "name";
//a data array to be used.
std::vector<int> ids;
ids.push_back(0);
ids.push_back(1);
try {
pqxx::connection c("dbname=mydb user=keutoi");
pqxx::work w(c);
c.prepare("example", "SELECT id FROM mytable WHERE id = $1 or id = $2");
pqxx::prepare::invocation w_invocation = w.prepared("example");
//dynamic array preparation
prep_dynamic(ids, w_invocation);
//executing prepared invocation.
pqxx::result r = w_invocation.exec();
w.commit();
std::cout << r.size() << std::endl;
}
catch(const std::exception &e)
{
std::cerr << e.what() << std::endl;
return 1;
}
return 0;
}
if you want to handle other data types use this function definition
template<class T> pqxx::prepare::invocation& prep_dynamic(std::vector<T> data, pqxx::prepare::invocation& inv)
{
for(auto data_val : data)
inv(data_val);
return inv;
}
Use pqxx::prepare::invocation where you can, and bind more values before execution, because it's more stable and error preventative, but there is a faster way as I describe it below.
I.
With invocation:
pqxx::nontransaction W(C);
std::string m_insertCommand = "INSERT INTO tableforperftest(column1, column2) VALUES";
unsigned int m_nCurrentRow = 32767;
for (size_t i = 0; i < m_nCurrentRow; i++)
{
unsigned int countOf$ = i * 2;
for (unsigned int i = 0; i < 2; ++i)
{
if (i == 0)
{
m_insertCommand += "(";
}
else
{
m_insertCommand += ", ";
}
m_insertCommand += "$";
std::stringstream ss;
ss << countOf$ + i + 1;
m_insertCommand += ss.str();
}
if(i < m_nCurrentRow - 1)
m_insertCommand += ") ,";
}
m_insertCommand += ")";
C.prepare("insert_into_db", m_insertCommand);
pqxx::prepare::invocation inv = W.prepared("insert_into_db");
for (size_t i = 0; i < m_nCurrentRow; i++)
{
inv(i)(i);
}
inv.exec();
II.
With stored procedure which gets more values for parameters:
CREATE OR REPLACE FUNCTION insertintoboosted(valuesforinsert TEXT) RETURNS VOID AS
$$
BEGIN
EXECUTE 'INSERT INTO tableforperftestproof(column1, column2) VALUES (' || valuesforinsert || ')';
END;
$$
LANGUAGE plpgsql;
Code:
for (size_t i = 0; i < m_nCurrentRow; i++)
{
if (i == 0)
ss << i << "," << i;
else
ss << "(" << i << "," << i;
if (i < m_nCurrentRow - 1)
ss << "),";
}
C.prepare("prep2", "select insertintoboosted($1::text)");
W.prepared("prep2")(ss).exec();
III.
With parameter bindings and execution for each time:
std::string m_insertCommand3 = "INSERT INTO tableforperftest(column1, column2) VALUES ($1, $2)";
C.prepare("insert_into_db3", m_insertCommand3);
for (size_t i = 0; i < m_nCurrentRow; i++)
{
W.prepared("insert_into_db3")(i)(i).exec();
}
To compare the solutions with 32767 inserts:
Invocation: --> Elapsed: 0.250292s
Stored Proc: --> Elapsed: 0.154507s
Parameter binding + execution each time: --> Elapsed: 29.5566s

Create structs with names generated at runtime and refer to them within program

I have a set of datafiles stored within a directory.
eg.
./FT/Fourier_1
./FT/Fourier_2
./FT/Fourier_3
...
My code initially generates a list of the paths to these files.
std::string fileStringSearch="Fourier";
std::stringstream resultFileName;
std::vector<std::string> fileList;
int numLines=0;
DIR *parentDirPointer;
struct dirent *dp;
if ((parentDirPointer = opendir("FT")) == NULL)
{
std::cout << "Unable to open the parent (FT) directory" << std::endl;
return(3);
}
while ((dp = readdir(parentDirPointer)) != NULL)
{
std::string testFileName = dp->d_name;
if (testFileName.find(fileStringSearch) != std::string::npos)
{
resultFileName << "FT/" << dp->d_name;
std::string blahblah=resultFileName.str();
fileList.push_back(blahblah);
numLines++;
resultFileName.str(std::string());
resultFileName.clear();
}
};
sort(fileList.begin(),fileList.end());
for (unsigned n=0; n<fileList.size(); ++n)
{
resultFileName << fileList.at(n) << std::endl;
}
FTFilePaths = resultFileName.str();
I then want to read data from each file and store it in some format which I can later read, use in functions, etc.
My current thought is a struct - I have:
struct Wavenum_struct {
std::string name;
double timestep;
double indexToK_Multiplier;
std::vector<double> Amp_k;
std::vector<double> dFTdt_prev_to_this;
}
and at a later point in my program I read these files like :
for (int lineCounter=0; lineCounter < numLines; lineCounter++)
{
getline(readPath, FilePathLine);
c = FilePathLine.c_str();
readFile.open(c);
extern Wavenum_struct c;
c.name = FilePathLine;
//print_name(c);
while(getline (readFile, lineToRead))
{
readFile >> value;
c.Amp_k.push_back(value);
}
//print_amps(c);
}
The commented out print_amps(c); will work just fine with a function something like:
void print_amps(struct Wavenum_struct t)
{
for(int i=0; i<t.Amp_k.size(); i++)
{
std::cout << i << ": " << t.Amp_k[i] << std::endl;
}
}
but this obviously prints the amplitudes of every struct, and only once. If I want to refer to specific structs later in the program, and print them selectively, (or not print them, but use them for some function) eg
void dFTdt(struct Wavenum_struct t_i, struct Wavenum_struct t_i1)
{
int numWavenums = t_i.Amp_k.size();
double dt = t_i1.timestep - t_i.timestep;
double dFTdt[numWavenums];
for (int k=0; k<numWavenums; k++)
{
dFTdt[k] = (t_i1.Amp_k[k] - t_i.Amp_k[k])/dt;
}
t_i1.dFTdt_prev_to_this.assign(dFTdt, dFTdt+numWavenums);
}
then I can't seem to get anywhere, since c returns to being recognised as a const * char outside of the for loop, and anything I've tried like:
print_amps(reinterpret_cast<Wavenum_struct*>("FT/Fourier_1"));
refuses to compile.
I assume that what I need might involve pointers to functions and print_name() as a function of the struct, but this doesn't seem likely to help me with my void dFTdt() function, and I still don't know how to refer to a given struct once c no longer gives the name of that struct.
Is this in any way possible?
In this function (which really should have a name):
for (int lineCounter=0; lineCounter < numLines; lineCounter++)
{
getline(readPath, FilePathLine);
c = FilePathLine.c_str();
readFile.open(c);
extern Wavenum_struct c;
c.name = FilePathLine;
//print_name(c);
while(getline (readFile, lineToRead))
{
readFile >> value;
c.Amp_k.push_back(value);
}
//print_amps(c);
}
apart from the fact that you appear to be reusing the variable name "c" (which is unseemly), your Wavenum_struct c gets overwritten with each iteration through the loop, so even if you have this "extern" set up correctly, the most you will retain is the last one. You have to save these Wavenums somewhere, so why not use a vector?
std::vector<Wavenum_struct> wavenums;
for (int lineCounter=0; lineCounter < numLines; lineCounter++)
{
...
//print_amps(c);
wavenums.push_back(c);
}