My son is implementing a server on a Raspberry Pi that allows control of the GPIO pins via a network connection. He has discovered some strange behaviour, which at first seemed like a bug (but see answer below).
First, the OS being used is Raspbian, a version of Debian Linux. He is using the standard system file to control the GPIO ports.
We start with a GPIO pin, e.g. pin 17, in a non-exported state. For example,
echo "17" > /sys/class/gpio/unexport
Now, if the server is asked to turn on pin 17, it does the following:
Opens the /sys/class/gpio/export, writes "17" to it, and closes the export file
Open the /sys/class/gpio/gpio17/direction file for read, examines it to see if it is set as input or output. Closes the file. Then, if necessary, re-opens the file for write and writes "out" to the file, to set the pin as an output pin, and closes the direction file.
At this point, we should be able to open /sys/class/gpio/gpio17/value for write, and write a "1" to it.
However, the permissions on the /sys/class/gpio/gpio17/value file exists but the group permissions is read-only. If we put in a "sleep" in order to wait for a fraction of a second, the permissions change so the group permission has write permissions.
I would have expected that the OS should not return from the write to the direction file until it had set the permissions on the value file correctly.
Why is this happening? It seems like a bug. Where should I report this (with more detail...)? See answer below.
What follows are the relevant bits of code. The code has been edited and paraphrased a bit, but it is essentially what is being used. (Keep in mind it's the code of a grade 12 student trying to learn C++ and Unix concepts):
class GpioFileOut
{
private:
const string m_fName;
fstream m_fs;
public:
GpioFileOut(const string& sName)
: m_fName(("/sys/class/gpio/" + sName).c_str())
{
m_fs.open(m_fName.c_str());
if (m_fs.fail())
{
cout<<"ERROR: attempted to open " << m_fName << " but failed" << endl << endl;
}
else
{
cout << m_fName << " opened" << endl;
}
}
~GpioFileOut()
{
m_fs.close();
cout << m_fName << " closed" << endl << endl;
}
void reOpen()
{
m_fs.close();
m_fs.open(m_fName);
if (m_fs.fail())
{
cout<<"ERROR: attempted to re-open " << m_fName << " but failed" << endl << endl;
}
else
{
cout << m_fName << " re-opened" << endl;
}
}
GpioFileOut& operator<<(const string &s)
{
m_fs << s << endl;
cout << s << " sent to " << m_fName << endl;
return *this;
}
GpioFileOut& operator<<(int n)
{
return *this << to_string(n); //ostringstream
}
bool fail()
{
return m_fs.fail();
}
};
class GpioFileIn
{
private:
ifstream m_fs;
string m_fName;
public:
GpioFileIn(const string& sName)
: m_fs( ("/sys/class/gpio/" + sName).c_str())
, m_fName(("/sys/class/gpio/" + sName).c_str())
{
if (m_fs <= 0 || m_fs.fail())
{
cout<<"ERROR: attempted to open " << m_fName << " but failed" << endl;
}
else
{
cout << m_fName << " opened" << endl;
}
}
~GpioFileIn()
{
m_fs.close();
cout << m_fName << " closed" << endl << endl;
}
void reOpen()
{
m_fs.close();
m_fs.open(m_fName);
if (m_fs <= 0 || m_fs.fail())
{
cout<<"ERROR: attempted to re-open " << m_fName << " but failed" << endl;
}
else
{
cout << m_fName << " re-opened" << endl;
}
}
GpioFileIn& operator>>(string &s)
{
m_fs >> s;
cout << s << " read from " << m_fName << endl;
return *this;
}
bool fail()
{
return m_fs.fail();
}
};
class Gpio
{
public:
static const bool OUT = true;
static const bool IN = false;
static const bool ON = true;
static const bool OFF = false;
static bool setPinDirection(const int pinId, const bool direction)
{
GpioFileOut dirFOut(("gpio" + to_string(pinId) + "/direction").c_str());
if (dirFOut.fail())
{
if (!openPin(pinId))
{
cout << "ERROR! Pin direction not set: Failed to export pin" << endl;
return false;
}
dirFOut.reOpen();
}
dirFOut << (direction == OUT ? "out" : "in");
}
static bool setPinValue(const int pinId, const bool pinValue)
{
string s;
{
GpioFileIn dirFIn(("gpio" + to_string(pinId) + "/direction").c_str());
if (dirFIn.fail())
{
if (!openPin(pinId))
{
cout << "ERROR! Pin not set: Failed to export pin"<<endl;
return false;
}
dirFIn.reOpen();
}
dirFIn >> s;
}
if (strncmp(s.c_str(), "out", 3) == 0)
{
struct stat _stat;
int nTries = 0;
string fname("/sys/class/gpio/gpio"+to_string(pinId)+"/value");
for(;;)
{
if (stat(fname.c_str(), &_stat) == 0)
{
cout << _stat.st_mode << endl;
if (_stat.st_mode & 020 )
break;
}
else
{
cout << "stat failed. (Did the pin get exported successfully?)" << endl;
}
cout << "sleeping until value file appears with correct permissions." << endl;
if (++nTries > 10)
{
cout << "giving up!";
return false;
}
usleep(100*1000);
};
GpioFileOut(("gpio" + to_string(pinId) + "/value").c_str()) << pinValue;
return true;
}
return false;
}
static bool openPin(const int pinId)
{
GpioFileOut fOut("export");
if (fOut.fail())
return false;
fOut << to_string(pinId);
return true;
}
}
int main()
{
Gpio::openPin(17);
Gpio::setPinDirection(17, Gpio::OUT)
Gpio::setPinValue(17, Gpio::ON);
}
The key point is this: without the for(;;) loop that stat's the file, the execution fails, and we can see the permissions change on the file within 100ms.
From a kernel perspective, the 'value' files for each GPIO pin that has been exported are created with mode 0644 and ownership root:root. The kernel does not do anything to change this when you write to the 'direction' file.
The behavior you are describing is due to the operation of the systemd udev service. This service listens for events from the kernel about changes in device state, and applies rules accordingly.
When I tested on my own Pi, I did not experience the behavior you described - the gpio files in /sys are all owned by root:root and have mode 0644, and did not change regardless of direction. However I am running Pidora, and I could not find any udev rules in my system relating to this. I am assuming that Raspbian (or maybe some package you have added to your system) has added such rules.
I did find this thread where some suggested rules are mentioned. In particular this rule which would have the effect you describe:
SUBSYSTEM=="gpio*", PROGRAM="/bin/sh -c 'chown -R root:gpio /sys/class/gpio; chmod -R 770 /sys/class/gpio; chown -R root:gpio /sys/devices/virtual/gpio; chmod -R 770 /sys/devices/virtual/gpio'"
You can search in /lib/udev/rules.d, /usr/lib/udev/rules.d and /etc/udev/rules.d for any files containing the text 'gpio' to confirm if you have such rules. By the way, I would be surprised if the change was triggered by changing direction on the pin, more likely by the action of exporting the pin to userspace.
The reason you need to sleep for a while after exporting the device is that until your process sleeps, the systemd service may not get a chance to run and action the rules.
The reason it is done like this, rather than just having the kernel take care of it, is to push policy implementation to userspace in order to provide maximum flexibility without overly complicating the kernel itself.
See: systemd-udevd.service man page and udev man page.
Related
The problem is it prints the full name but not the rest of the lines about the person.
Could someone, please guide me?
I do really appreciate your help!
auto itr = find(my_vec.begin(), my_vec.end(), search );
if(itr != my_vec.end())
{
std::cout << "Match found " << search << std::endl;
std::cout << "\nFull name: " << search << std::endl;
} else {
std::cout << "Match not found "<< std::endl;
}
There are a few style problems with your code:
No need to explicitly initialize strings, they will be empty by default (see here).
Keep a consistent style. For example, either always start brackets in the same line as the function signature or in the next line.
No need to close the file explicitly at the end of the function, this is done when the object goes out of scope (see (destructor) here).
No need to include <map> and <iomanip> headers.
Don't keep unused variables.
Give suggestive names to your variables.
Do not return error codes to the OS when the app is working as it should. Not finding a name is not an error, is it?
It seems your file has 6 entries per contact, so all you have to do is print 5 more lines. You do not need to store the lines in a vector, just parse and print them as you go. Here is an example:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
void findContact(std::string fullName, std::string contactListPath) {
std::ifstream inFile{contactListPath};
if (!inFile) {
std::cerr << "File could not be open!" << std::endl;
return;
}
std::string line;
while (std::getline(inFile, line)) {
if (line == fullName) {
std::cout << "Match found: \n";
std::cout << "\nFull name: " << fullName;
std::cout << "\nAddress: " << (std::getline(inFile, line), line);
std::cout << "\nE-mail: " << (std::getline(inFile, line), line);
std::cout << "\nPhone: " << (std::getline(inFile, line), line);
std::cout << "\nBirthday: " << (std::getline(inFile, line), line);
std::cout << "\nNote: " << (std::getline(inFile, line), line) << std::endl;
return;
}
}
std::cout << "Match not found " << std::endl;
}
int main() {
std::string fullName;
std::string contactListPath;
std::cout << "Enter full name to search: ";
std::getline(std::cin, fullName);
std::cout << "Enter path to contact list: ";
std::getline(std::cin, contactListPath);
findContact(fullName, contactListPath);
return 0;
}
If every entry contains 6 lines. Then you can print all the lines starting from the line that you found like:
auto itr = find(my_vec.begin(), my_vec.end(), search );
if(itr != my_vec.end())
{
std::cout << "Match found " << std::endl;
// print the next 6 lines
for(int remaining = 6;remaining > 0 && itr!=my_vec.end(); itr++,remaining--) {
std::cout << *itr << std::endl;
}
} else {
std::cout << "Match not found "<< std::endl;
}
It does not crash so there is no core to analyse. It simply stops.
I have experimented multiple times. It stops exactly after 2 hours.
OS : qnx6.5.0
LIBs : ZeroMQ and Protobuf
I just have a single thread, it looks something like this :
dummyFrontEnd::dummyFrontEnd():context(1),socket(context,ZMQ_PUB) {
}
void dummyFrontEnd::Init()
{
socket.connect("tcp://127.0.0.1:5555");
cout << "Connecting .... " << endl;
}
void dummyFrontEnd::SendCANalyserTable(const std::string& filename)
{
...
zmq::message_t create_values( protoTable.ByteSizeLong()
+ sizeof(uint16_t)
);
*((uint16_t*)create_values.data()) = TABLEMSG_ID; // ID
protoTable.SerializeToArray( create_values.data()
+ sizeof(uint16_t),
protoTable.ByteSizeLong()
);
try {
socket.send(create_values,ZMQ_NOBLOCK);
}
catch (int e){
std::cout << "SPD exception e : "
<< e
<< std::endl;
}
protoTable.clear_columnvalues();
usleep(1);
}
}
void main(){
...
...
while(1) {
if (arguments.canalyser_filename != "") {
dmyFntEnd.SendCANalyserTable(arguments.canalyser_filename);
if (arguments.verbose) {
cout << "DummyFrontEnd"
<< "completed sending CANalyser table"
<< endl;
}
}
}
...
...
}
For a school c++ lab (using microsoft visual studio, hence the system("pause")) I am making a program that will let a user input an email address and the program will spit out the username (before '#') and the site type, either the type based on the last three letters of the address (com is commercial ventures) or the last two letter country code (us is united states).
#include <iostream>
#include <string>
using namespace std;
void getemail(string &email);
void finduser(string email);
void findsitetype(string email);
int main()
{
string email;
getemail(email);
finduser(email);
findsitetype(email);
system("pause");
return 0;
}
void getemail(string &email)
{
cout << "Please enter your email address: ";
cin >> email;
cout << endl;
}
void finduser(string email)
{
int index = email.find('#');
cout << "Username: ";
for (int i = 0; i < index; i++)
cout << email[i];
cout << endl << endl;
}
void findsitetype(string email)
{
int truesize = size(email);
string lastthree;
for (int i = 0; i < 3; i++)
{
lastthree[i] = email[truesize - i];
}
cout << "Site type: ";
if (lastthree == "edu")
cout << "Educational institutions";
if (lastthree == "org")
cout << "Not-for-profit organizations";
if (lastthree == "gov")
cout << "Government entities";
if (lastthree == "mil")
cout << "Military installations";
if (lastthree == "net")
cout << "Network service providers";
if (lastthree == "com")
cout << "Commercial ventures";
if (email[truesize - 2] == '.')
cout << "Country Code " << email[truesize - 1] << email[truesize];
}
When I run the code, it spits out the username but there seems to be a fatal error when finding the site type. I think it has something to do with my incorrect string use? Any help appreciated.
Debug Assertion Failed!
Program: C:\windows\SYSTEM32\MSVCP140D.dll File: c:\program files
(x86)\microsoft visual studio 14.0\vc\include\xstring Line: 1681
Expression: string subscript out of range
For more information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
There are a couple things wrong with your code, (1) to get the length of a string, use the length() function, so:
int truesize = size(email);
should be
int truesize = email.length();
I changed your if statements to else ifs because if one of the condition statements evaluates to true, we shouldn't need to check the rest of them.
(2) your for loop is grabbing the email extension in the reverse direction, change:
for (int i = 0; i < 3; i++)
{
lastthree[i] = email[truesize - i];
}
to
lastthree = email.substr(truesize-3, truesize);
I have written a small bluetooth server and client progrem using winsock
I am not able to figure out why the client is not getting connected to the server. Both are running in different pcs and
both are paired through bluetooth.
The server code is
void server()
{
SOCKET server_socket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM), new_socket;
if (server_socket == INVALID_SOCKET)
{
cout << "socket creation failed...Error code : " << WSAGetLastError() << endl;
Sleep(2000);
return;
}
cout << "socket created" << endl;
SOCKADDR_BTH sa, sa2;
int channel = 0, len=sizeof(sa2);
memset(&sa, 0, sizeof(SOCKADDR_BTH));
sa.addressFamily = AF_BTH;
sa.port = channel & 0xff;
//bind
if (bind(server_socket, (SOCKADDR *)&sa, sizeof(sa)))
{
cout << "Binding failed...Error code : " << WSAGetLastError() << endl;
closesocket(server_socket);
Sleep(2000);
return;
}
cout << "binding done" << endl;
cout << "\nWaiting for client" << endl;
listen(server_socket, 3);
new_socket = accept(server_socket, (sockaddr *)&sa2, &len);
cout<<"connection accepted";
}
The client code is
void client()
{
SOCKET client_socket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
int channel = 0;
BTH_ADDR bt_addr;
char* server_address = "34:02:86:26:c1:62";
if (client_socket == INVALID_SOCKET)
{
cout << "socket creation failed...Error code : " << WSAGetLastError() << endl;
Sleep(2000);
return;
}
cout << "socket created" << endl;
if (str2ba(server_address, &bt_addr) == 1)
{
cout << "address conversion error..." << endl;
Sleep(2000);
return;
}
SOCKADDR_BTH sa;
sa.addressFamily = AF_BTH;
sa.port = channel & 0xff;
sa.btAddr = bt_addr;
cout << "\nconnecting..." << endl;
if (connect(client_socket, (sockaddr *)&sa, sizeof(sockaddr)))
{
cout << "Error in connecting...Error code : " << WSAGetLastError() << endl;
closesocket(client_socket);
Sleep(2000);
return;
}
cout << "\nConnected" << endl;
Sleep(2000);
}
int str2ba(char *str_bt_addr, BTH_ADDR *bt_addr)//for converting string to bluetooth address
{
unsigned int addr[6];
if (sscanf_s(str_bt_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
&addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6)
{
return 1;
}
*bt_addr = 0;
BTH_ADDR tmpaddr;
int i;
for (i = 0;i < 6;++i)
{
tmpaddr = (BTH_ADDR)(addr[i] & 0xff);
*bt_addr = ((*bt_addr) << 8) + tmpaddr;
}
return 0;
}
Why are these not getting connected? What am I missing?
Please help me.
Thanks in advance for any help.
In my short Bluetooth experience, the problem is normally somewhere in the SOCKADDR_BTH declarations.
I hard coded the MAC Address of each Endpoint: "38:2D:E8:B9:FA:EB" in Hex
RemoteEndPoint.btAddr = BTH_ADDR(0x382DE8B9FAEB);
Also make sure your Ports are the same on each Endpoint, I used:
RemoteEndPoint.port = 0;
and
LocalEndpoint.port = 0;
I have some code here: C++ WinSock Bluetooth Connection - AT Command - Error Received where I have an issue also.
Bluetooth is not as easy as some may think, thus the lack of answers received by the OP's
This program is a nightmare, it wont even give me errors when ran, visual studios tells me nothing and i need some help
#include <iostream>
using namespace std;
class Textbook
{
private:
char *aPtr;
char *tPtr;
int yearPub;
int numPages;
char bookType;
public:
Textbook(char *, char *, int, int, char);
void display();
void operator=(Textbook&);
};
Textbook::Textbook(char*string = NULL, char*string2 = NULL, int ypub = 0, int npages = 0, char btype = 'X')
{
aPtr = new char[strlen(string) +1];
strcpy(aPtr, string);
tPtr = new char[strlen(string2) +1];
strcpy(tPtr, string2);
yearPub = ypub;
numPages = npages;
bookType = btype;
}
void Textbook::display()
{
cout << "The name of the author is: " << *aPtr << endl;
cout << "The Title of the book is: " << *tPtr << endl;
cout << "The year it was published is: " << yearPub << endl;
cout << "The number of pages is: " << numPages << endl;
cout << "The initial of the title is: " << bookType << endl;
return;
}
void Textbook::operator=(Textbook& newbook)
{
if(aPtr != NULL) //check that it exists
delete(aPtr);// delete if neccessary
aPtr = new char[strlen(newbook.aPtr) + 1];
strcpy(aPtr, newbook.aPtr);
if(tPtr != NULL) //check that it exists
delete(tPtr); // delete if neccessary
tPtr = new char[strlen(newbook.tPtr) + 1];
strcpy(tPtr, newbook.tPtr);
yearPub = newbook.yearPub;
numPages = newbook.numPages;
bookType = newbook.bookType;
}
void main()
{
Textbook book1("sehwag", "Programming Methods", 2009, 200, 'H');
Textbook book2("Ashwin", "Security Implementation", 2011, 437, 'P');
Textbook book3;
book1.display();
book2.display();
book3.display();
book3 = book1;
book2 = book3;
book1.display();
book2.display();
book3.display();
}
im not sure if the problem lies in the default constructor but that's about the only thing i could think of, but im not sure at all on how to fix it.
Problem is with the default-parameters in the constructor.
You can't do those kind of operations with NULL-pointers.
Textbook book3;
crashes your program.
Change:
cout << "The name of the author is: " << *aPtr << endl;
cout << "The Title of the book is: " << *tPtr << endl;
to:
cout << "The name of the author is: " << aPtr << endl;
cout << "The Title of the book is: " << tPtr << endl;
Also change:
aPtr = new char[strlen(string) +1];
strcpy(aPtr, string);
to:
if (string != NULL)
{
aPtr = new char[strlen(string) +1];
strcpy(aPtr, string);
}
else
{
aPtr = new char[1];
aPtr[0] = '\0';
}
and ditto for tptr and string2.
The reason you need this checking is because you have NULL as a default value for your two string inputs, so when you call the constructor with no arguments (as is the case with book3) these strings are just NULL pointers. Calling functions such as strlen or strcat with a NULL pointer will result in an exception as you have seen.
Ideally you should not be using C-style strings with C++ - use C++ strings instead - this will help to avoid problems such as the above.