Find the answer to your Linux question:
Page 1 of 2 1 2 LastLast
Results 1 to 10 of 15
Hello, I am having the following problem. The following code works fine on my P.C. Ubuntu x64, and on a jetway mini-itx board with an atom processor. The problem is, ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Sep 2010
    Location
    Montgomery, AL
    Posts
    27

    [SOLVED] ioctl TIOCMGET call doesn't detect TIOCM_CTS


    Hello,

    I am having the following problem. The following code works fine on my P.C. Ubuntu x64, and on a jetway mini-itx board with an atom processor. The problem is, the same code doesn't work on the intel equivalent of the jetway board. I thought the maybe, I didn't have the port configured right, so I turned on Hardware Flow control and also tried turning on the modem bits I needed with TIOCMBIS. Neither worked. Here is the code. There are two threads, one of them, respsponding to the client, and using the RTS and DTR pins to power two relays. The other, manages listening to CTS and DSR for input. Here is the class with the first thread.

    Code:
    /*
     * DigitalIOCore.cpp
     *
     *  Created on: Nov 1, 2010
     *      Author: jonathan
     */
    
    #include "DigitalIOCore.h"
    #include "DeviceInfo.h"
    #include "NetworkSettings.h"
    #include "ClientSocket.h"
    #include "SocketException.h"
    
    int currentBitState;
    
    DigitalIOCore::DigitalIOCore() : status(0), set_bits1(0), set_bits2(0)
    {
    	//Grab the DeviceInfo from config file;
    	DeviceInfo device;
    
    	if((fd = open(device.getIOPort().c_str(), O_RDWR | O_NDELAY)) >= 0)
    	{
    		PWaitAndSignal m(port_mutex);
    		input_engine = new DigitalInputEngine(&port_mutex, fd);
    
    		input_engine->input1_received.connect(sigc::mem_fun(this, &DigitalIOCore::FireInput1));
    		input_engine->input2_received.connect(sigc::mem_fun(this, &DigitalIOCore::FireInput2));
    		input_engine->input3_received.connect(sigc::mem_fun(this, &DigitalIOCore::FireInput3));
    	}
    
    	if(fd >= 0)
    		input_engine->Resume();
    }
    
    DigitalIOCore::~DigitalIOCore()
    {
    	input_engine->end_thread = true;
    	input_engine->Terminate();
    
    	delete input_engine;
    
    	close(fd);
    }
    
    bool DigitalIOCore::Output1(bool on_off)
    {
    	if(on_off)
    	{
    		//set the bits to TIOCM_DTR and include TIOCM_RTS if it is on so not to undo Output2 if it is running
    		set_bits1 = TIOCM_DTR;
    		currentBitState = set_bits1 | set_bits2;
    
    		//hold the semaphore for as short a time as possible since the input thread will need this serial port as well.
    		PWaitAndSignal m(port_mutex);
    		int test = ioctl(fd, TIOCMSET, &currentBitState);
    		ioctl(fd, TIOCMGET, &status);
    		return status & TIOCM_DTR;
    	}
    	else
    	{
    		//set the bits back to TIOCM_DTR being off, but do not undo TIOCM_RTS if it is on.
    		set_bits1 = 0;
    		currentBitState = set_bits1 | set_bits2;
    		//hold the semaphore for as short a time as possible since the input thread will need this serial port as well.
    		PWaitAndSignal m(port_mutex);
    		ioctl(fd, TIOCMSET, &currentBitState);
    
    		ioctl(fd, TIOCMGET, &status);
    		return ~(status & TIOCM_DTR);
    	}
    }
    
    bool DigitalIOCore::Output2(bool on_off)
    {
    	if(on_off)
    	{
    		//set the bits to TIOCM_RTS and include TIOCM_DTS if it is on so not to undo Output1 if it is running
    		set_bits2 = TIOCM_RTS;
    		currentBitState = set_bits1 | set_bits2;
    
    		//hold the semaphore for as short a time as possible since the input thread will need this serial port as well.
    		PWaitAndSignal m(port_mutex);
    		ioctl(fd, TIOCMSET, &currentBitState);
    		ioctl(fd, TIOCMGET, &status);
    
    		return status & TIOCM_RTS;
    	}
    	else
    	{
    		//set the bits back to TIOCM_RTS being off, but do not undo TIOCM_DTS if it is on.
    		set_bits2 = 0;
    		currentBitState = set_bits1 | set_bits2;
    
    		//hold the semaphore for as short a time as possible since the input thread will need this serial port as well.
    		PWaitAndSignal m(port_mutex);
    		ioctl(fd, TIOCMSET, &currentBitState);
    		ioctl(fd, TIOCMGET, &status);
    		return ~(status & TIOCM_RTS);
    	}
    }
    
    void DigitalIOCore::FireInput1()
    {
    	NetworkSettings network;
    	vector<string> devicesToRemove;
    
    	for(list<string>::iterator iter = clients.begin(); iter != clients.end(); iter++)
    	{
    		//we need to handle the case where a registered client goes offline. In that case the client will be removed from the list.
    		try
    		{
    			ClientSocket sock(*iter, 35100);
    
    			sock << network.getIPv4Address() + "&0&";
    		}
    		catch(SocketException ex)
    		{
    			devicesToRemove.push_back(*iter);
    		}
    	}
    
    	for(vector<string>::iterator iter = devicesToRemove.begin(); iter != devicesToRemove.end(); iter++)
    	{
    		clients.remove(*iter);
    	}
    }
    
    void DigitalIOCore::FireInput2()
    {
    	NetworkSettings network;
    	vector<string> devicesToRemove;
    
    	for(list<string>::iterator iter = clients.begin(); iter != clients.end(); iter++)
    	{
    		//we need to handle the case where a registered client goes offline. In that case the client will be removed from the list.
    		try
    		{
    			ClientSocket sock(*iter, 35100);
    
    			sock << network.getIPv4Address() + "&1&";
    		}
    		catch(SocketException ex)
    		{
    			devicesToRemove.push_back(*iter);
    		}
    	}
    
    	for(vector<string>::iterator iter = devicesToRemove.begin(); iter != devicesToRemove.end(); iter++)
    	{
    		clients.remove(*iter);
    	}
    }
    
    void DigitalIOCore::FireInput3()
    {
    	NetworkSettings network;
    	vector<string> devicesToRemove;
    
    	//we need to handle the case where a registered client goes offline. In that case the client will be removed from the list.
    	for(list<string>::iterator iter = clients.begin(); iter != clients.end(); iter++)
    	{
    		try
    		{
    			ClientSocket sock(*iter, 35100);
    
    			sock << network.getIPv4Address() + "&2&";
    		}
    		catch(SocketException ex)
    		{
    			devicesToRemove.push_back(*iter);
    		}
    	}
    
    	for(vector<string>::iterator iter = devicesToRemove.begin(); iter != devicesToRemove.end(); iter++)
    	{
    		clients.remove(*iter);
    	}
    }
    
    void DigitalIOCore::RegisterClientForInput(string ipAddress)
    {
    	clients.push_back(ipAddress);
    }
    
    void DigitalIOCore::RemoveClientFromInput(string ipAddress)
    {
    	clients.remove(ipAddress);
    }
    here is the second, handling the input
    Code:
    /*
     * DigitalInputEngine.cpp
     *
     *  Created on: Nov 1, 2010
     *      Author: jonathan
     */
    
    #include "DigitalInputEngine.h"
    
    
    DigitalInputEngine::DigitalInputEngine(PMutex* port_mutex, int fd) : PThread (1000, AutoDeleteThread, HighestPriority, "DigitalInputEngine"),
    	end_thread(false)
    {
    	mutex = port_mutex;
    	serial = fd;
    
    	if(DEBUG)
    	{
    		std::cout << "Input Engine constructed.\n";
    	}
    }
    
    DigitalInputEngine::~DigitalInputEngine()
    {
    }
    
    void DigitalInputEngine::Main()
    {
    	int temp = 0;
    	ioctl(serial, TIOCMSET, &temp);
    
    	if(DEBUG)
    		std::cout << "Serial set to 0\n";
    
    	while(!end_thread)
    	{
    		if(DEBUG)
    				std::cout << "Iteration of Thread Called\n";
    
    		int bytes = 0;
    
    		if(serial >= 0)
    		{
    			//hold the semaphore for as short a time as possible since, since the output thread will need this serial port as well.
    			PWaitAndSignal m(*mutex);
    			//send 127 because this will ensure a constant positive voltage since all bits will be high.
    			//The tx pin is being used for source voltage.
    
    			//we will not be using the tx pin for source any more, so this has been commented out.
    			//char data[] = {127, 127, 127, 127, 127, 127, 127, 127};
    			//int test = write(serial, data , 8);
    			ioctl(serial, TIOCMGET, &bytes);
    
    			if(DEBUG)
    				std::cout << "Data written out and read on serial port\n";
    		}
    
    		if((bytes & TIOCM_CTS) && (bytes & TIOCM_DSR))
    		{
    			if(DEBUG)
    				std::cout << "Input 3 fired\n";
    
    			input3_received.emit();
    			this->Sleep(100);
    		}
    
    		else if (bytes & TIOCM_CTS)
    		{
    			if(DEBUG)
    				std::cout << "Input 1 fired\n";
    
    			input1_received.emit();
    			this->Sleep(100);
    		}
    
    		else if (bytes & TIOCM_DSR)
    		{
    			if(DEBUG)
    				std::cout << "Input 2 fired\n";
    
    			input2_received.emit();
    		    this->Sleep(100);
    		}
    
    		else
    		{
    			//give the other thread time to grab the semaphore
    			this->Sleep(5);
    		}
    	}
    }

    As I said, this works perfectly on all boards I have tested except for the intel board. I have already tried adding

    int sigs = TIOCM_RTS | TIOCM_DTR | TIOCM_CTS | TIOCM_DSR;
    ioctl(fd, TIOCMBIS, &sigs);

    struct termios options;
    tcgetattr(fd, &options);

    options.c_cflag |= CRTSCTS;
    tcsetattr(fd, TCSANOW, &options);

    after the open call, and it didn't help.

    Thanks for your help!
    Last edited by JHenson; 04-06-2011 at 06:40 PM.

  2. #2
    Just Joined!
    Join Date
    Sep 2010
    Location
    Montgomery, AL
    Posts
    27
    oh yeah, and the mini-itx boards are running a version of Crunch Bang that I stripped down to run as an embeded system.

  3. #3
    Just Joined!
    Join Date
    Sep 2010
    Location
    Montgomery, AL
    Posts
    27
    woops! I forgot to mention the actual problem. When I put +12v dc from the source voltage onto the CTS pin it does not set the pin to high. This does work however on the DSR pin. I only have this problem on the Intel board.

  4. #4
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,459
    Please! When you post code, DO put it inside code blocks! Like this:

    Code:
    /*
     * DigitalIOCore.cpp
     *
     *  Created on: Nov 1, 2010
     *      Author: jonathan
     */
    
    #include "DigitalIOCore.h"
    #include "DeviceInfo.h"
    #include "NetworkSettings.h"
    #include "ClientSocket.h"
    #include "SocketException.h"
    
    int currentBitState;
    
    DigitalIOCore::DigitalIOCore() : status(0), set_bits1(0), set_bits2(0)
    {
    	//Grab the DeviceInfo from config file;
    	DeviceInfo device;
    
    	if((fd = open(device.getIOPort().c_str(), O_RDWR | O_NDELAY)) >= 0)
    	{
    		PWaitAndSignal m(port_mutex);
    		input_engine = new DigitalInputEngine(&port_mutex, fd);
    
    		input_engine->input1_received.connect(sigc::mem_fun(this, &DigitalIOCore::FireInput1));
    		input_engine->input2_received.connect(sigc::mem_fun(this, &DigitalIOCore::FireInput2));
    		input_engine->input3_received.connect(sigc::mem_fun(this, &DigitalIOCore::FireInput3));
    	}
    
    	if(fd >= 0)
    		input_engine->Resume();
    }
    
    DigitalIOCore::~DigitalIOCore()
    {
    	input_engine->end_thread = true;
    	input_engine->Terminate();
    
    	delete input_engine;
    
    	close(fd);
    }
    
    bool DigitalIOCore::Output1(bool on_off)
    {
    	if(on_off)
    	{
    		//set the bits to TIOCM_DTR and include TIOCM_RTS if it is on so not to undo Output2 if it is running
    		set_bits1 = TIOCM_DTR;
    		currentBitState = set_bits1 | set_bits2;
    
    		//hold the semaphore for as short a time as possible since the input thread will need this serial port as well.
    		PWaitAndSignal m(port_mutex);
    		int test = ioctl(fd, TIOCMSET, &currentBitState);
    		ioctl(fd, TIOCMGET, &status);
    		return status & TIOCM_DTR;
    	}
    	else
    	{
    		//set the bits back to TIOCM_DTR being off, but do not undo TIOCM_RTS if it is on.
    		set_bits1 = 0;
    		currentBitState = set_bits1 | set_bits2;
    		//hold the semaphore for as short a time as possible since the input thread will need this serial port as well.
    		PWaitAndSignal m(port_mutex);
    		ioctl(fd, TIOCMSET, &currentBitState);
    
    		ioctl(fd, TIOCMGET, &status);
    		return ~(status & TIOCM_DTR);
    	}
    }
    
    bool DigitalIOCore::Output2(bool on_off)
    {
    	if(on_off)
    	{
    		//set the bits to TIOCM_RTS and include TIOCM_DTS if it is on so not to undo Output1 if it is running
    		set_bits2 = TIOCM_RTS;
    		currentBitState = set_bits1 | set_bits2;
    
    		//hold the semaphore for as short a time as possible since the input thread will need this serial port as well.
    		PWaitAndSignal m(port_mutex);
    		ioctl(fd, TIOCMSET, &currentBitState);
    		ioctl(fd, TIOCMGET, &status);
    
    		return status & TIOCM_RTS;
    	}
    	else
    	{
    		//set the bits back to TIOCM_RTS being off, but do not undo TIOCM_DTS if it is on.
    		set_bits2 = 0;
    		currentBitState = set_bits1 | set_bits2;
    
    		//hold the semaphore for as short a time as possible since the input thread will need this serial port as well.
    		PWaitAndSignal m(port_mutex);
    		ioctl(fd, TIOCMSET, &currentBitState);
    		ioctl(fd, TIOCMGET, &status);
    		return ~(status & TIOCM_RTS);
    	}
    }
    
    void DigitalIOCore::FireInput1()
    {
    	NetworkSettings network;
    	vector<string> devicesToRemove;
    
    	for(list<string>::iterator iter = clients.begin(); iter != clients.end(); iter++)
    	{
    		//we need to handle the case where a registered client goes offline. In that case the client will be removed from the list.
    		try
    		{
    			ClientSocket sock(*iter, 35100);
    
    			sock << network.getIPv4Address() + "&0&";
    		}
    		catch(SocketException ex)
    		{
    			devicesToRemove.push_back(*iter);
    		}
    	}
    
    	for(vector<string>::iterator iter = devicesToRemove.begin(); iter != devicesToRemove.end(); iter++)
    	{
    		clients.remove(*iter);
    	}
    }
    
    void DigitalIOCore::FireInput2()
    {
    	NetworkSettings network;
    	vector<string> devicesToRemove;
    
    	for(list<string>::iterator iter = clients.begin(); iter != clients.end(); iter++)
    	{
    		//we need to handle the case where a registered client goes offline. In that case the client will be removed from the list.
    		try
    		{
    			ClientSocket sock(*iter, 35100);
    
    			sock << network.getIPv4Address() + "&1&";
    		}
    		catch(SocketException ex)
    		{
    			devicesToRemove.push_back(*iter);
    		}
    	}
    
    	for(vector<string>::iterator iter = devicesToRemove.begin(); iter != devicesToRemove.end(); iter++)
    	{
    		clients.remove(*iter);
    	}
    }
    
    void DigitalIOCore::FireInput3()
    {
    	NetworkSettings network;
    	vector<string> devicesToRemove;
    
    	//we need to handle the case where a registered client goes offline. In that case the client will be removed from the list.
    	for(list<string>::iterator iter = clients.begin(); iter != clients.end(); iter++)
    	{
    		try
    		{
    			ClientSocket sock(*iter, 35100);
    
    			sock << network.getIPv4Address() + "&2&";
    		}
    		catch(SocketException ex)
    		{
    			devicesToRemove.push_back(*iter);
    		}
    	}
    
    	for(vector<string>::iterator iter = devicesToRemove.begin(); iter != devicesToRemove.end(); iter++)
    	{
    		clients.remove(*iter);
    	}
    }
    
    void DigitalIOCore::RegisterClientForInput(string ipAddress)
    {
    	clients.push_back(ipAddress);
    }
    
    void DigitalIOCore::RemoveClientFromInput(string ipAddress)
    {
    	clients.remove(ipAddress);
    }
    here is the second, handling the input
    Code:
    /*
     * DigitalInputEngine.cpp
     *
     *  Created on: Nov 1, 2010
     *      Author: jonathan
     */
    
    #include "DigitalInputEngine.h"
    
    
    DigitalInputEngine::DigitalInputEngine(PMutex* port_mutex, int fd) : PThread (1000, AutoDeleteThread, HighestPriority, "DigitalInputEngine"),
    	end_thread(false)
    {
    	mutex = port_mutex;
    	serial = fd;
    
    	if(DEBUG)
    	{
    		std::cout << "Input Engine constructed.\n";
    	}
    }
    
    DigitalInputEngine::~DigitalInputEngine()
    {
    }
    
    void DigitalInputEngine::Main()
    {
    	int temp = 0;
    	ioctl(serial, TIOCMSET, &temp);
    
    	if(DEBUG)
    		std::cout << "Serial set to 0\n";
    
    	while(!end_thread)
    	{
    		if(DEBUG)
    				std::cout << "Iteration of Thread Called\n";
    
    		int bytes = 0;
    
    		if(serial >= 0)
    		{
    			//hold the semaphore for as short a time as possible since, since the output thread will need this serial port as well.
    			PWaitAndSignal m(*mutex);
    			//send 127 because this will ensure a constant positive voltage since all bits will be high.
    			//The tx pin is being used for source voltage.
    
    			//we will not be using the tx pin for source any more, so this has been commented out.
    			//char data[] = {127, 127, 127, 127, 127, 127, 127, 127};
    			//int test = write(serial, data , 8);
    			ioctl(serial, TIOCMGET, &bytes);
    
    			if(DEBUG)
    				std::cout << "Data written out and read on serial port\n";
    		}
    
    		if((bytes & TIOCM_CTS) && (bytes & TIOCM_DSR))
    		{
    			if(DEBUG)
    				std::cout << "Input 3 fired\n";
    
    			input3_received.emit();
    			this->Sleep(100);
    		}
    
    		else if (bytes & TIOCM_CTS)
    		{
    			if(DEBUG)
    				std::cout << "Input 1 fired\n";
    
    			input1_received.emit();
    			this->Sleep(100);
    		}
    
    		else if (bytes & TIOCM_DSR)
    		{
    			if(DEBUG)
    				std::cout << "Input 2 fired\n";
    
    			input2_received.emit();
    		    this->Sleep(100);
    		}
    
    		else
    		{
    			//give the other thread time to grab the semaphore
    			this->Sleep(5);
    		}
    	}
    }
    That will keep the indents, and avoid turning some symbol sets into smileys.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  5. #5
    Just Joined!
    Join Date
    Sep 2010
    Location
    Montgomery, AL
    Posts
    27
    Thanks, I was wondering how to do that.

  6. #6
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,459
    Anyway, regarding your problem. Have you considered that it is possible that the Intel board is not supporting hardware flow control on that port? Or that there is some sort of low-level configuration option (i/o instructions) to enable it. Anyway, I have seen boards where there is no hw flow control, just transmit, receive, and ground. What does the Intel web site say about the board? The specs should be there I would think.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  7. #7
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,459
    Quote Originally Posted by JHenson View Post
    Thanks, I was wondering how to do that.
    When you hit the "quote" button to make a reply, if there are any special blocks inside the quoted text, they will show up, which is how you can figure some of this stuff out (how to use the forums effectively). Anyway, welcome to the forums.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  8. #8
    Just Joined!
    Join Date
    Sep 2010
    Location
    Montgomery, AL
    Posts
    27
    Quote Originally Posted by Rubberman View Post
    Anyway, regarding your problem. Have you considered that it is possible that the Intel board is not supporting hardware flow control on that port? Or that there is some sort of low-level configuration option (i/o instructions) to enable it. Anyway, I have seen boards where there is no hw flow control, just transmit, receive, and ground. What does the Intel web site say about the board? The specs should be there I would think.
    I will work on getting the specs. It is certainly possible that it does not support hardware flow control, though I would think that would kill my DSR pin as well. The fact that my other modem bits are working confuses me, since I would think that no hardware control would kill those off as well. As to whether or not there are some i/o instructions I can set, that is largely the reason I posted this here instead of the hardware and peripherals section--I don't know and I am hoping that that is my problem.

    Thanks for the swift reply and form posting help.

  9. #9
    Just Joined!
    Join Date
    Sep 2010
    Location
    Montgomery, AL
    Posts
    27
    correction. RTS is the other hardware flow control bit, and it does work. However, I am turning it on as an output and not listening for an outside voltage to set it to high. DSR is not related to Hardware Flow control, so that doesn't prove anything.

    Question, if hardware flow control is not supported on this board, would I still be able to set RTS to high from my code? I know for certain it works, as I am driving a relay with it and I just tested it.

  10. #10
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,459
    Quote Originally Posted by JHenson View Post
    correction. RTS is the other hardware flow control bit, and it does work. However, I am turning it on as an output and not listening for an outside voltage to set it to high. DSR is not related to Hardware Flow control, so that doesn't prove anything.

    Question, if hardware flow control is not supported on this board, would I still be able to set RTS to high from my code? I know for certain it works, as I am driving a relay with it and I just tested it.
    Probably not. It may be that there is a problem with the port/board. Ok. Digging back into my brain (I haven't done RS-232 bit twiddling for a looong time), here is something. DSR is actually part of the DTE/DCE RS-232 flow control standard protocols. The DSR line is used by DCE equipment to indicate to the DTE that the DCE is ready to receive data. The RTS line is used by the DTE equipment to tell the DCE to get ready to receive data. So, it may be that in your case, that the port is a DTE only, and not a DCE device. DTE flow control lines are DTR and RTS. DCE flow control lines are DSR and CTS. I don't think that you need to fiddle with the ring indicator and carrier detect lines and such.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

Page 1 of 2 1 2 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •