不断地读写管道以一种方式工作,而以另一种方式工作一次

发布于 2025-01-12 03:51:30 字数 10407 浏览 4 评论 0原文

我正在 Raspberry Pi 4 上用 C++ 编写一个程序来命令一些电机并通过 GPIO 引脚获取速度传感器的信息。

为此,需要有一个带有“叉子”的主控制程序。 父进程完成所有计算,子进程通过 SPI 通信不断发送和接收数据(发送和接收数据是同时完成的,库不允许执行其中之一)。

在每个循环中,子级读取父级发送的数据(此部分有效),并将输入上读取的数据(有效一次)发送回父级。

实际上,我用电缆连接了“读取”数据,这样我就可以控制输入并确定它们的状态。

在下面的示例中,我将请求的信息提供给程序,让父级写入子级,该方法有效(选择电机 0/15,速度为 0,方向 0=停止且不停止程序

)第一次尝试,它告诉我读取的数据是10,这是正确的。

然后,我将跳线移动到另一个值(在本例中为 15),但在第二次尝试时它仍然给我 10,

我检查了我的程序,来自孩子的写入收到了良好的数据,这实际上是管道有问题,并且我无法理解它。看起来管道已关闭...

这是终端视图

Terminal window

问题出在父行

if (read(fdCP[0], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in Parent read :'( " <<'\n'; }

和子行

 //If here I print the content of "In0", it is correct and fitting what the program read
 if(write(fdCP[1], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in child write :'( " <<'\n'; }; //sending data through the pipe

之间,这里是为了可读性而剥离了绝大多数程序的程序。

#include <bcm2835.h> //SPI & GPIO communication library
#include <stdio.h>
#include <unistd.h>     //got fork() in it
#include <sys/wait.h>
#include <vector>
#include <iostream> //for Cout to display stuff
#include <thread>   //for multithreading
#include <string.h>
#include <time.h>

using std::vector;
int SRDInit();
char* SendReceiveData(char* SpiOut, char* SpiIn); //Defines the existance of this function and will check in the compiled stuff if it exists (spoiler : it does)
int SRDClose();
int main(int MotNb, int Spd1, int Dir1)
{
    //Fork and multiprocessing stuff
    bool EndThis = false;   //Variable for ending the continous look of sending and receiving data from shift registers
    //SPI Communication buffers and data storages
    char SpiOut[2]={0,0}; //Defining the char to send by SPI and set it to 0
    short int In0[2] = {0}; //Char array for receiving data
    int Sp1 = 0;        // iteration variable for speed
    short int SpdDir[4] = {0, 0, 0, 0}; //creates a table with 4 ints inside 0 for motor number, 1 for Speed, 2 for Dirrection and 3 for killing the child

//###################################################################################   
//Actual beginning of the program
//###################################################################################
        int fdPC[2];            //File descriptor for the piping Parent to child
        int fdCP[2];            //File descriptor for the piping Child to Parent
        std::cout << "Init FD" << '\n';
        if (pipe(fdPC) == -1){          //creating the pipe for communication with the second program sending and receiving data
            //fd[0] = Read fd[1]=write
            std::cout << "an error occured while creating the pipe Parent to Child" << std::endl;
            return 1;
        }
        if (pipe(fdCP) == -1){          //creating the pipe for communication with the second program sending and receiving data
            //fd[0] = Read fd[1]=write
            std::cout << "an error occured while creating the pipe Child to Parent" << std::endl;
            return 1;
        }
        std::cout << "Forking" << '\n';
        int id = fork();        //forking the program to create a second one playing on another processor
        std::cout << "Forked ID = " << id << '\n';
        if (id < 0){
            std::cout << "An error occured while forking :'(" << std::endl;
        }
        else if (id > 0){           //if in the main process
            std::cout << "Enter Main process" << '\n';
//###################################################################################   
//Main process.
//###################################################################################
            close (fdPC[0]);        //closing the read side of the Parent to child pipe
            close (fdCP[1]);        //closing the write side of the child to parent pipe
            fcntl(fdPC[1], F_SETFL,O_NONBLOCK);
            fcntl(fdCP[0], F_SETFL,O_NONBLOCK);
            int MotNb = 0;          //variable for the number of the motor to be modified
            short int OldIn0[2] = {0, 0};
            short int NewIn0[2] = {0, 0};
            
            while(EndThis == false){
                std::cout << "Gi'me Motor 0-15" <<'\n';
                std::cin >> MotNb;
                std::cout << "Gi'me speed" <<'\n';
                std::cin >> Spd1;
                std::cout << "Gi'me dirrection 0=3= stop 1=fwd 2=bwd" <<'\n';
                std::cin >> Dir1;
                std::cout << "Stop that? Y/N" <<'\n';       //check if we want to close the program
                std::cin >> EndProg;
                
                SpdDir[0] = MotNb;          //storing the Motor number
                SpdDir[1] = Spd1;           //storing the speed
                SpdDir[2] = Dir1;           // storing the dirrection

                if(write(fdPC[1], SpdDir, sizeof(short int)*4) == -1) { std::cout << "Something went wrong in Parent write :'( " <<'\n'; }      //Writing through the pipe to send data to the Child
                if (read(fdCP[0], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in Parent read :'( " <<'\n'; }

                NewIn0[0] = In0[0];
                NewIn0[1] = In0[1];
                if (NewIn0[0] != OldIn0[0] || NewIn0[1] != OldIn0[1]) {
                    std::cout << "SOMETHING CHANGED !!! Old In0 = " << +OldIn0[0]<< +OldIn0[1] << " and NewIn0 = " << +NewIn0[0]<< +NewIn0[1] << '\n';  
                    OldIn0[0] = NewIn0[0];
                    OldIn0[1] = NewIn0[1];
                }
                
                if (SpdDir[3] > 0){
                    EndThis = true;
                    std::cout << "Stopping main" <<'\n';        //check if we want to close the program
                }
            }   //End of PARENT while
            write(fdPC[1], SpdDir, sizeof(int)*3);      //Writing through the pipe to send data to the Child for ending the program
            //End of main program, closing everything and freeing memory because we're tidy people
            close (fdPC[1]);        //closing the write side of the Parent to child pipe
            close (fdCP[0]);        //closing the read side of the child to parent pipe
            if (wait(NULL) == -1){              //wait for the child to finish working == -1
                std::cout << "No children to wait for" << std::endl;
            }else {
                std::cout << "waiting for children to finish" << '\n';
            }
        }
        else{                   // if in the secondary process
            std::cout << "Enter child process" << '\n';
//###################################################################################   
//Child process. Send Speed and dirrection requested and receive data (because no choice for receiving)
//###################################################################################
            close (fdPC[1]);        //closing the write side of the Parent to child pipe
            close (fdCP[0]);        //closing the read side of the child to parent pipe
            fcntl(fdPC[0], F_SETFL,O_NONBLOCK);
            fcntl(fdCP[1], F_SETFL,O_NONBLOCK);
            
            int MotNb = 0;          //variable for the number of the motor to be modified
            //Actual beginning of child program
            char* SpiIn=(char*)malloc(sizeof(char)*17);     //creation de la data qui sera échangée malloc est fermé apres l'appel a la fonction
            if(SpiIn==NULL){
                perror("Char allocation of SendReceiveData FAILED !!");
                return 1;
            }
            while(EndThis == false){
                read(fdPC[0], SpdDir, sizeof(short int)*4);//read data from the pipe put them in SpdDir varaible
                MotNb = SpdDir[0];          //storing the motor nb
                Spd1 = SpdDir[1];           //storing the speed
                Dir1 = SpdDir[2];           // storing the dirrection
                
        //Some amazing coding has been deleted here ;)

                    In0Raw = SendReceiveData(SpiOut, SpiIn);        //Send data in "SpiOut" and puts the data received in In0Raw
                    In0[0] = In0Raw[1];     //Data is no read in the logical direction TBC
                    In0[1] = In0Raw[0];     //Data is no read in the logical direction TBC

                //If here I print the content of "In0", it is correct and fitting what the program read
                if(write(fdCP[1], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in child write :'( " <<'\n'; }; //sending data through the pipe
                sleep(1);
                if (SpdDir[3] > 0){
                    EndThis = true;
                std::cout << "Ending child" << '\n';
                }
            }   //End of CHILD while
            //End of child program, closing everything and freeing memory because we're tidy people
            close (fdPC[0]);        //closing the read side of the Parent to child pipe
            close (fdCP[1]);        //closing the write side of the child to parent pipe
            free(In0Raw);           //free memory allocated to In0Raw for "SendReceiveData"
            std::cout << "Child ended" << '\n';
            exit(EXIT_SUCCESS);
        }
    
//###################################################################################
    if (id > 0){
        std::cout << "End of program enter a key and press ENTER to finish" <<'\n';
        std::cin >> Spd1;
        SRDClose();
        free(In0Raw);       //release memory of the pointer just in case
    }
    return 0;
}

如果您想知道“SendReceiveData”是什么,它只是一个非常小的函数,通过 SPI 连接发送和接收数据。它工作正常,这真的很基本;)

我知道问题出在哪里,但我完全不知道问题是什么。看起来管道在从子级到父级写入一次后就关闭了,但它在另一个方向上工作得很好,从父级到子级发送指令

(如果需要,我可以复制整个代码而不是这段摘录)

谢谢提前寻求您的帮助! :)

I'm writing a program in C++ on a Raspberry Pi 4 to command some motors and get back the informations of speed sensors through the GPIO pins.

To do so, there is a main control program with a "fork" in it.
The parent process does all the calculation and the child process is constantly sending and receiving data through a SPI communication (sending and receiving data are done at the same time and the library don't allow to do either one or the other).

On each loop, the child reads data sent by the parent (this part works) and it sends back the data read on the inputs (works once) to the parent.

I actually have the "read" data wired with cables so I can control the inputs and be sure of their states.

In the following example, I give the requested infos to the program to have the parent write to the child, which works (choosing motor 0/15, having a speed of 0 and a direction 0=stopped and not stopping the program)

On the first try, it tells me the read data is 10, which is correct.

I then move my jumping cables to another value (15 in this case) but it still gives me 10 on the second try

I checked my program, the write from the child receives the good data, it is really the piping that has a problem and I can't get my head around it. It looks like the Pipe gets closed...

Here is the terminal view

Terminal window

The problem is between the parent lines

if (read(fdCP[0], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in Parent read :'( " <<'\n'; }

and the child lines

 //If here I print the content of "In0", it is correct and fitting what the program read
 if(write(fdCP[1], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in child write :'( " <<'\n'; }; //sending data through the pipe

And here is the programm stripped down of its vast majority for readability.

#include <bcm2835.h> //SPI & GPIO communication library
#include <stdio.h>
#include <unistd.h>     //got fork() in it
#include <sys/wait.h>
#include <vector>
#include <iostream> //for Cout to display stuff
#include <thread>   //for multithreading
#include <string.h>
#include <time.h>

using std::vector;
int SRDInit();
char* SendReceiveData(char* SpiOut, char* SpiIn); //Defines the existance of this function and will check in the compiled stuff if it exists (spoiler : it does)
int SRDClose();
int main(int MotNb, int Spd1, int Dir1)
{
    //Fork and multiprocessing stuff
    bool EndThis = false;   //Variable for ending the continous look of sending and receiving data from shift registers
    //SPI Communication buffers and data storages
    char SpiOut[2]={0,0}; //Defining the char to send by SPI and set it to 0
    short int In0[2] = {0}; //Char array for receiving data
    int Sp1 = 0;        // iteration variable for speed
    short int SpdDir[4] = {0, 0, 0, 0}; //creates a table with 4 ints inside 0 for motor number, 1 for Speed, 2 for Dirrection and 3 for killing the child

//###################################################################################   
//Actual beginning of the program
//###################################################################################
        int fdPC[2];            //File descriptor for the piping Parent to child
        int fdCP[2];            //File descriptor for the piping Child to Parent
        std::cout << "Init FD" << '\n';
        if (pipe(fdPC) == -1){          //creating the pipe for communication with the second program sending and receiving data
            //fd[0] = Read fd[1]=write
            std::cout << "an error occured while creating the pipe Parent to Child" << std::endl;
            return 1;
        }
        if (pipe(fdCP) == -1){          //creating the pipe for communication with the second program sending and receiving data
            //fd[0] = Read fd[1]=write
            std::cout << "an error occured while creating the pipe Child to Parent" << std::endl;
            return 1;
        }
        std::cout << "Forking" << '\n';
        int id = fork();        //forking the program to create a second one playing on another processor
        std::cout << "Forked ID = " << id << '\n';
        if (id < 0){
            std::cout << "An error occured while forking :'(" << std::endl;
        }
        else if (id > 0){           //if in the main process
            std::cout << "Enter Main process" << '\n';
//###################################################################################   
//Main process.
//###################################################################################
            close (fdPC[0]);        //closing the read side of the Parent to child pipe
            close (fdCP[1]);        //closing the write side of the child to parent pipe
            fcntl(fdPC[1], F_SETFL,O_NONBLOCK);
            fcntl(fdCP[0], F_SETFL,O_NONBLOCK);
            int MotNb = 0;          //variable for the number of the motor to be modified
            short int OldIn0[2] = {0, 0};
            short int NewIn0[2] = {0, 0};
            
            while(EndThis == false){
                std::cout << "Gi'me Motor 0-15" <<'\n';
                std::cin >> MotNb;
                std::cout << "Gi'me speed" <<'\n';
                std::cin >> Spd1;
                std::cout << "Gi'me dirrection 0=3= stop 1=fwd 2=bwd" <<'\n';
                std::cin >> Dir1;
                std::cout << "Stop that? Y/N" <<'\n';       //check if we want to close the program
                std::cin >> EndProg;
                
                SpdDir[0] = MotNb;          //storing the Motor number
                SpdDir[1] = Spd1;           //storing the speed
                SpdDir[2] = Dir1;           // storing the dirrection

                if(write(fdPC[1], SpdDir, sizeof(short int)*4) == -1) { std::cout << "Something went wrong in Parent write :'( " <<'\n'; }      //Writing through the pipe to send data to the Child
                if (read(fdCP[0], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in Parent read :'( " <<'\n'; }

                NewIn0[0] = In0[0];
                NewIn0[1] = In0[1];
                if (NewIn0[0] != OldIn0[0] || NewIn0[1] != OldIn0[1]) {
                    std::cout << "SOMETHING CHANGED !!! Old In0 = " << +OldIn0[0]<< +OldIn0[1] << " and NewIn0 = " << +NewIn0[0]<< +NewIn0[1] << '\n';  
                    OldIn0[0] = NewIn0[0];
                    OldIn0[1] = NewIn0[1];
                }
                
                if (SpdDir[3] > 0){
                    EndThis = true;
                    std::cout << "Stopping main" <<'\n';        //check if we want to close the program
                }
            }   //End of PARENT while
            write(fdPC[1], SpdDir, sizeof(int)*3);      //Writing through the pipe to send data to the Child for ending the program
            //End of main program, closing everything and freeing memory because we're tidy people
            close (fdPC[1]);        //closing the write side of the Parent to child pipe
            close (fdCP[0]);        //closing the read side of the child to parent pipe
            if (wait(NULL) == -1){              //wait for the child to finish working == -1
                std::cout << "No children to wait for" << std::endl;
            }else {
                std::cout << "waiting for children to finish" << '\n';
            }
        }
        else{                   // if in the secondary process
            std::cout << "Enter child process" << '\n';
//###################################################################################   
//Child process. Send Speed and dirrection requested and receive data (because no choice for receiving)
//###################################################################################
            close (fdPC[1]);        //closing the write side of the Parent to child pipe
            close (fdCP[0]);        //closing the read side of the child to parent pipe
            fcntl(fdPC[0], F_SETFL,O_NONBLOCK);
            fcntl(fdCP[1], F_SETFL,O_NONBLOCK);
            
            int MotNb = 0;          //variable for the number of the motor to be modified
            //Actual beginning of child program
            char* SpiIn=(char*)malloc(sizeof(char)*17);     //creation de la data qui sera échangée malloc est fermé apres l'appel a la fonction
            if(SpiIn==NULL){
                perror("Char allocation of SendReceiveData FAILED !!");
                return 1;
            }
            while(EndThis == false){
                read(fdPC[0], SpdDir, sizeof(short int)*4);//read data from the pipe put them in SpdDir varaible
                MotNb = SpdDir[0];          //storing the motor nb
                Spd1 = SpdDir[1];           //storing the speed
                Dir1 = SpdDir[2];           // storing the dirrection
                
        //Some amazing coding has been deleted here ;)

                    In0Raw = SendReceiveData(SpiOut, SpiIn);        //Send data in "SpiOut" and puts the data received in In0Raw
                    In0[0] = In0Raw[1];     //Data is no read in the logical direction TBC
                    In0[1] = In0Raw[0];     //Data is no read in the logical direction TBC

                //If here I print the content of "In0", it is correct and fitting what the program read
                if(write(fdCP[1], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in child write :'( " <<'\n'; }; //sending data through the pipe
                sleep(1);
                if (SpdDir[3] > 0){
                    EndThis = true;
                std::cout << "Ending child" << '\n';
                }
            }   //End of CHILD while
            //End of child program, closing everything and freeing memory because we're tidy people
            close (fdPC[0]);        //closing the read side of the Parent to child pipe
            close (fdCP[1]);        //closing the write side of the child to parent pipe
            free(In0Raw);           //free memory allocated to In0Raw for "SendReceiveData"
            std::cout << "Child ended" << '\n';
            exit(EXIT_SUCCESS);
        }
    
//###################################################################################
    if (id > 0){
        std::cout << "End of program enter a key and press ENTER to finish" <<'\n';
        std::cin >> Spd1;
        SRDClose();
        free(In0Raw);       //release memory of the pointer just in case
    }
    return 0;
}

If you're wondering what "SendReceiveData" is, it's just a very tiny function sending and receiving data through the SPI connection. It works fine, it's really basic ;)

I know where the problem lies, but I have absolutely no idea what the problem is. It looks like the pipe is closed wfter writing it once from Child to Parent, but it works very fine in the other direction, to send instructions from Parent to Child

(If needed, I can copy the whole code instead of this extract)

Thanks by advance for your help ! :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柠檬色的秋千 2025-01-19 03:51:30

我已阅读文档(由朋友提供) write() 手册 这没有帮助,但可能对某人有用。

我尝试使用 errno 来理解错误,我检查了文档 errno 手册并且很有用。

write() 发回错误“资源暂时不可用”,对应于“EAGAIN”,但最重要的是“可能与 EWOULDBLOCK 的值相同”
对应于“操作将阻塞”

我搜索并找到了一个讨论,其中答案是“缓冲区已满”

所以,我询问是否可以覆盖 write() 文件描述符中的数据,答案是“否”: '(
是否可以覆盖 write() 数据?

在再次写入之前,您必须读取文件描述符中的数据。

显然,线程对此更好,我必须调查。

希望这对某人有帮助。

I've read the documentation (given by a friend) write() manual which did not help, but can be useful to someone.

I tried to understand the error, using errno for which I checked the documentation errno manual and was useful.

The write() sent back the error "Resource temporarily unavailable" which corresponds to "EAGAIN" but, most importantly it is said "may be the same value as EWOULDBLOCK"
corresponding to "Operation would block"

I searched and found a discussion where the answer was "the buffer is full"

So, I asked if it is possible to overwrite a data in the write() file descriptor and the answer is "no" :'(
Is it possible to overwrite a write() data?

You have to read a data in a file descriptor before writing again.

Apparently, threads are better for that, I have to invesstigate.

Hoping this helps someone.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文