USB VCP connection fails occasionally - c

My question is quite simple:
I operate 20 CP210x (Silicon Lab) devices over an industrial 20 Port USB Hub.
In one of about 1000 trials to open the port I get a problem: The call to
CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
is blocking and doesn't return. In this case it doesn't help to repeat or to restart my software. Only plugging out/in the device helps.
Of course the port name is including backslashes, as required for higher COM Port numbers. The port is closed without getting an error after each communication by
CloseHandle(comport_p);
I could give more details on my source, but think, that the relevant parts are the mentioned lines. Is there something else I have to consider in my software or could there be a driver problem?

Related

Get signal level of the connected WiFi network

Using wpa_supplicant 2.4 on ARM Debian.
Is there a way to get signal level, in decibels or percents, of the wireless network I’m currently connected to?
STATUS command only returns the following set of values: bssid, freq, ssid, id, mode, pairwise_cipher, group_cipher, key_mgmt, wpa_state, ip_address, p2p_device_address, address, uuid
I can run SCAN afterwards, wait for results and search by SSID. But that’s slow and error-prone, I'd like to do better.
The driver should already know that information (because connected, and adjusting transmit levels for energy saving), is there a way to just query for that?
This question is not about general computing hardware and software. I'm using wpa_supplicant through a C API defined in wpa_ctrl.h header, interacting with the service through a pair of unix domain sockets (one for commands, another one for unsolicited events).
One reason I don’t like my current SCAN + SCAN_RESULT solution, it doesn’t work for hidden SSID networks. Scan doesn’t find the network, therefore I’m not getting signal level this way. Another issue is minor visual glitch at application startup. My app is launched by systemd, After=multi-user.target. Unless it’s the very first launch, Linux is already connected to Wi-Fi by then. In my app’s GUI (the product will feature a touch screen), I render a phone-like status bar, that includes WiFi signal strength icon. Currently, it initially shows minimal level (I know it's connected because STATUS command shows SSID), only after ~1 second I’m getting CTRL-EVENT-SCAN-RESULTS event from wpa_supplicant, run SCAN_RESULT command and update signal strength to the correct value.
On the API level my code is straightforward. I have two threads for that, both call wpa_ctrl_open, the command thread calls wpa_ctrl_request, the event thread has an endless loop that calls poll passing wpa_ctrl_get_fd() descriptor and POLLIN event mask, followed by wpa_ctrl_pending and wpa_ctrl_recv.
And here's the list of files in /sys/class/net/wlan0:
./mtu
./type
./phys_port_name
./netdev_group
./flags
./power/control
./power/async
./power/runtime_enabled
./power/runtime_active_kids
./power/runtime_active_time
./power/autosuspend_delay_ms
./power/runtime_status
./power/runtime_usage
./power/runtime_suspended_time
./speed
./dormant
./name_assign_type
./proto_down
./addr_assign_type
./phys_switch_id
./dev_id
./duplex
./gro_flush_timeout
./iflink
./phys_port_id
./addr_len
./address
./operstate
./carrier_changes
./broadcast
./queues/rx-0/rps_flow_cnt
./queues/rx-0/rps_cpus
./queues/rx-1/rps_flow_cnt
./queues/rx-1/rps_cpus
./queues/rx-2/rps_flow_cnt
./queues/rx-2/rps_cpus
./queues/rx-3/rps_flow_cnt
./queues/rx-3/rps_cpus
./queues/tx-0/xps_cpus
./queues/tx-0/tx_maxrate
./queues/tx-0/tx_timeout
./queues/tx-0/byte_queue_limits/limit
./queues/tx-0/byte_queue_limits/limit_max
./queues/tx-0/byte_queue_limits/limit_min
./queues/tx-0/byte_queue_limits/hold_time
./queues/tx-0/byte_queue_limits/inflight
./queues/tx-1/xps_cpus
./queues/tx-1/tx_maxrate
./queues/tx-1/tx_timeout
./queues/tx-1/byte_queue_limits/limit
./queues/tx-1/byte_queue_limits/limit_max
./queues/tx-1/byte_queue_limits/limit_min
./queues/tx-1/byte_queue_limits/hold_time
./queues/tx-1/byte_queue_limits/inflight
./queues/tx-2/xps_cpus
./queues/tx-2/tx_maxrate
./queues/tx-2/tx_timeout
./queues/tx-2/byte_queue_limits/limit
./queues/tx-2/byte_queue_limits/limit_max
./queues/tx-2/byte_queue_limits/limit_min
./queues/tx-2/byte_queue_limits/hold_time
./queues/tx-2/byte_queue_limits/inflight
./queues/tx-3/xps_cpus
./queues/tx-3/tx_maxrate
./queues/tx-3/tx_timeout
./queues/tx-3/byte_queue_limits/limit
./queues/tx-3/byte_queue_limits/limit_max
./queues/tx-3/byte_queue_limits/limit_min
./queues/tx-3/byte_queue_limits/hold_time
./queues/tx-3/byte_queue_limits/inflight
./tx_queue_len
./uevent
./statistics/rx_fifo_errors
./statistics/collisions
./statistics/rx_errors
./statistics/rx_compressed
./statistics/rx_dropped
./statistics/tx_packets
./statistics/tx_errors
./statistics/rx_missed_errors
./statistics/rx_over_errors
./statistics/tx_carrier_errors
./statistics/tx_heartbeat_errors
./statistics/rx_crc_errors
./statistics/multicast
./statistics/tx_fifo_errors
./statistics/tx_aborted_errors
./statistics/rx_bytes
./statistics/tx_compressed
./statistics/tx_dropped
./statistics/rx_packets
./statistics/tx_bytes
./statistics/tx_window_errors
./statistics/rx_frame_errors
./statistics/rx_length_errors
./dev_port
./ifalias
./ifindex
./link_mode
./carrier
You can get the signal level of the connected wifi by wpa_supplicant cmd SIGNAL_POLL
The wpa_supplicant would return:
RSSI=-60
LINKSPEED=867
NOISE=9999
FREQUENCY=5745
The value of the RSSI is the signal level.
You can get the signal level of the connected wifi by wpa_supplicant cmd BSS <bssid>.
About the bssid of the connected wifi, you can get from wpa_supplicant cmd STATUS.
https://android.googlesource.com/platform/external/wpa_supplicant_8/+/622b66d6efd0cccfeb8623184fadf2f76e7e8206/wpa_supplicant/ctrl_iface.c#1986
For iw compatible devices:
Following command gives the current station(aka AP) signal strength:
iw dev wlp2s0 station dump -v
If you need C API, just dig the source code of iw.
After a quick glance, the function you need is here
For broadcom devices, try search broadcom wl. It is close source, don't know if C API is provided.

Serial COM Port not opening

I am trying to open the serial COM PORT in a Win32 Application. The port is opening correctly but I can send a receive bytes just if I previously opened it using Teraterm or Hyperterminal.
If I deactivate and activate the COM port from Device Manager (so the port is freshly unused) I need to simply open the COM port with Teraterm or Putty and afer I closed it and then run my software I can send and receive properly at anytime.
I am using Embarcadero X3 with FileMonkey to make the application compatible with MACOSX and Win32 at the same time. FileMonkey does not suuport VCL.
The same code is working fine on Builder 6 c++ using VCL but it should not influence it in anyway. My code is really simple.
This is a very weird behavior. Seems like I need to INIT the COM (I am using FTDI converter) before I can use it and when the PC restarts or I deactivate and activate back the COM from Device Manager it seems this INIT is vanished and I simply need to open up the COM to revive it using another Serial Software and then use my software.
Note: Once the port is INIT I have the full control from my software. I am sure my code is truly opening the COM port because the COM appears busy once the iNIT is done if I try to use it with other softwares. So no flase alarm and more the application is working on the other side so far.
I have this problem since long and I now decided to solve it!
This is my code:
// GLOBAL VARIABLES
HANDLE hComm = NULL;
COMMTIMEOUTS ctmoNew = {0}, ctmoOld;
DCB dcbCommPort;
hComm = CreateFile("COM2",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
0,
0);
if(hComm == INVALID_HANDLE_VALUE)
{
Application->Terminate();
}
GetCommTimeouts(hComm,&ctmoOld);
ctmoNew.ReadTotalTimeoutConstant = 100;
ctmoNew.ReadTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hComm, &ctmoNew);
dcbCommPort.DCBlength = sizeof(DCB);
GetCommState(hComm, &dcbCommPort);
BuildCommDCB("115200,N,8,1", &dcbCommPort);
SetCommState(hComm, &dcbCommPort);
Just a possibility, not certain that this is the problem.
But one difference to our typical COM port opening code is that we use SetupCom directly after the CreateFile succeeded and set our buffer sizes, typically 4KB.
Change your settings to:
"115200,NOPARITY,8,ONESTOPBIT"

Arduino and Windows serial communications issue?

I am working on a project that involves some 'c' serial communication implemented in Visual Studio 2010 Proffesional on a Windows 7 32-bit platform connected to an Arduino Mega device (to control some hardware **not relevant to problem). The code for this works 100%; the ONLY problem I'm having is that something very funny is going on with my serial communication.
The Visual C program is as follows.
HANDLE hDevice = CreateFile(L"COM5",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
0); //Open COM handle (create file)
if (hDevice !=INVALID_HANDLE_VALUE) //If COM3 connected
{
printf("Com port opened\n");
DCB lpTest;
GetCommState(hDevice,&lpTest);
lpTest.BaudRate = CBR_9600;
lpTest.ByteSize = 8;
lpTest.Parity = NOPARITY;
lpTest.StopBits = ONESTOPBIT;
SetCommState(hDevice,&lpTest);
DWORD btsIO;
WriteFile(hDevice,c1,strlen(c1),&btsIO,NULL);
CloseHandle(hDevice);
}
The output of this program is a text string, and I'm 100% happy with it (should end in Null, have x characters, etc.).
Typing the result obtained from this program in Serial Communicator, it does not seem to work! Using a COM spy program, I am able to obtain the "handshaking" protocols from the terminal application.
However, it seems that communication with the Arduino board works on HyperTerminal and not on Serial Communicator or any other serial applications (no handshaking, etc. is done on the Arduino board **not relevant).
The following "handshaking" was obtained from HyperTerminal (THIS WORKS!!)
*
COM port is opened
In/out queue size 8192/8192
Baud rate 9600
DTR on
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(DTR_CONTROL, CTS_HANDSHAKE, ERROR_ABORT), FlowReplace= (TRANSMIT_TOGGLE, RTS_HANDSHAKE, XOFF_CONTINUE), XonLimit=80, XoffLimit=200
Set timeouts: ReadInterval=10, ReadTotalTimeoutMultiplier=0, ReadTotalTimeoutConstant=0, WriteTotalTimeoutMultiplier=0, WriteTotalTimeoutConstant=5000
*
And this is from Serial Communicator (it does not work; incorrect and inconsistent numbers):
*
COM port is opened
In/out queue size 2048/2048
Baud rate 9600
RTS off
DTR off
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(), FlowReplace=(), XonLimit=80, XoffLimit=200
Set timeouts: ReadInterval=0, ReadTotalTimeoutMultiplier=0, ReadTotalTimeoutConstant=0, WriteTotalTimeoutMultiplier=0, WriteTotalTimeoutConstant=0
*
I can obviously see the differences but need to know how to make the Arduino board independent of these "handshaking" protocols. (DTR, timing, etc.)
And this is from my Visual Studio program (does not work; incorrect and inconsistent numbers)
*
COM port is opened
Baud rate 9600
RTS off
DTR off
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(), FlowReplace=(), XonLimit=80, XoffLimit=200
*
Thus I would like to get the Arduino board away from DTR and all handshaking, as I want the final implementation to "speak" directly from Visual Studio to the Arduino board.
*****UPDATE*******
Thanks for the advice, the thing is I do not understand is why an open source piece of hardware would require so much handshaking.. That is, why does only the worst serial terminal program work where Serial Communicator, advance serial monitor, terterm, terminal, etc. don't seem to work?
I have updated my code to mirror HyperTerminal exactly (complete all handshaking), but it does not seem to work!
Heres the updated code fragement:
HANDLE hDevice = CreateFile(L"COM5",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,0); //Open COM handle (create file)
if (hDevice !=INVALID_HANDLE_VALUE) //If COM3 connected
{
printf("Com port opened\n"); //Show it's open
DCB lpTest;
// Initialize the DCBlength member.
lpTest.DCBlength = sizeof (DCB);
GetCommState(hDevice,&lpTest); //com state
lpTest.BaudRate = CBR_9600;//load baud
lpTest.ByteSize = 8;// load no. bits
lpTest.Parity = NOPARITY;//parity
lpTest.StopBits = ONESTOPBIT;//stop bits
lpTest.fBinary = FALSE; // Binary mode; no EOF check
lpTest.fOutxCtsFlow = TRUE; // No CTS output flow control
lpTest.fOutxDsrFlow = FALSE; // No DSR output flow control
lpTest.fDtrControl = DTR_CONTROL_ENABLE; // DTR flow control type
lpTest.fDsrSensitivity = FALSE; // DSR sensitivity
lpTest.fTXContinueOnXoff = TRUE; // XOFF continues Tx
lpTest.fOutX = FALSE; // No XON/XOFF out flow control
lpTest.fInX = FALSE; // No XON/XOFF in flow control
lpTest.fErrorChar = FALSE; // Disable error replacement
lpTest.fNull = FALSE; // Disable null stripping
//lpTest.fRtsControl = RTS_CONTROL_ENABLE; //// RTS flow control
lpTest.fAbortOnError = TRUE; // Do not abort reads/writes on error
SetCommState(hDevice,&lpTest);
DWORD btsIO;
//ETC
}
The result is exactly the same as the working result from HyperTerminal except there is no timing conditions. However, I have used a 1 second delay after this code before closing the port.
Is the issue with my write statement?
WriteFile(hDevice,c1,strlen(c1),&btsIO,NULL); //Write string to serial
It seems like there is something fundamentally wrong that I am doing, and I can't find it!
*************UPDATE2***********
I have stumbled across something, how would I configure my program to send each character individually?
Visual Studio does not allow me to remove the Null or send one character in the code:
WriteFile(hDevice,c1,strlen(c1),&btsIO,NULL);//WRITE STRING TO SERIAL
How do I fix this problem? It seems like the Arduino board only accepts one character at a time.
I have edited the character variables to be one char, etc.!
*********UPDATE3********************
This are the results from monitoring the communication from Visual Studio 2010 (or serial communicator) and HyperTerminal. The issue is sending a bit at a time!
HyperTerminal:
Baud rate 9600
DTR on
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(DTR_CONTROL, CTS_HANDSHAKE, ERROR_ABORT), FlowReplace= (TRANSMIT_TOGGLE, RTS_HANDSHAKE, XOFF_CONTINUE), XonLimit=80, XoffLimit=200
Set timeouts: ReadInterval=10, ReadTotalTimeoutMultiplier=0, ReadTotalTimeoutConstant=0, WriteTotalTimeoutMultiplier=0, WriteTotalTimeoutConstant=5000
and Program/serial communication:
Baud rate 9600
DTR on
Data bits=8, Stop bits=1, Parity=None
Set chars: Eof=0x00, Error=0x00, Break=0x00, Event=0x00, Xon=0x11, Xoff=0x13
Handflow: ControlHandShake=(DTR_CONTROL, CTS_HANDSHAKE, ERROR_ABORT), FlowReplace= (TRANSMIT_TOGGLE, RTS_HANDSHAKE, XOFF_CONTINUE), XonLimit=80, XoffLimit=200
An X sec wait in program code.
It's been a long time since I last did serial work -- but it was very clear in those days that your software on the computer had to be configured exactly as the hardware device required. Your non-working example doesn't have DTR or RTS raised, and that's exactly what the board appears to require.
Since software on a full-powered computer is usually far easier to modify than hardware on an embedded board, it'd make sense to look into the configuration options available in your serial software -- any tolerable piece of software will have those settings to fiddle with. If not, I liked both Qmodem and ProComm, though I had friends that were adamant that Telix was the nicer tool. (I had some Trade Wars scripts for Telix that were amazing...)
Just as a suggestion: If you learn some C# and use .net API's it can be so easy to access serial port...

Toggling the CD (RLSD) signal line on a serial port in Windows C

I am trying to set the Carrier Detect (Receive Line Signal Detect) pin on a serial port being controlled by my Windows application. I am already able to set the RTS line high using this function:
EscapeCommFunction(handle, SETRTS);
and then subsequently clear it by using:
EscapeCommFunction(handle, CLRRTS);
I want to be able to do this exact same thing with the CD line, but no such SET/CLR flags exist for the EscapeCommFunction.
The PC serial port was designed from the viewpoint of a terminal, not a modem. The CD signal is an output from a modem and an input to a terminal. Even if the port hardware allows you to change the direction (of which I'm skeptical) the standard interface would not be programmed that way.
RS232 devices can be either a DTE (Data Terminal Equipment) or DCE (Data Communications Equipment). Examples of DCEs are modems, multiplexors and some line drivers (technically a modem), everything else including your computer is a DTE.
The DCD (RLSD) is an output from a DCE to indicate that has detected the carrier on the comms link i.e. can see the remote modem.
I know of no way to convert a DTE into a DCE with a standard serial port.

Serial Port Communication Issues (C code)

I recently tried to get access to a serial communication using a Bluetooth usb dongle.
I used the C code below, and keep getting error 5, which is “Access denied”. I am the administrator for the system (which seemed to be the common solution to this problem on the forums) and no other application is accessing the same port I am using (also another common solution). I’m running on a Windows Vista Home Basic 32bit system. I was wondering if anyone had a solution for this
My C code is:
HANDLE hComm;
hComm = CreateFile( _T("\\.\COM3"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hComm == INVALID_HANDLE_VALUE)
printf("Error number: %ld\n", GetLastError());
else
printf("success\n");
I don't know if this is your problem or not, but I suspect you need to escape the backslashes in the path, like so: "\\\\.\\COM3"
That does look like you have to escape your backslashes again. You can also verify that the COM port you're targeting exists on your system by using an object viewer, such as WinObj (http://technet.microsoft.com/en-us/sysinternals/bb896657.aspx), although I don't know if WinObj runs on Vista.
In my experience the backslashes are not needed
hComm = CreateFile( _T("COM3"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
Thanks for the tips but it turns out the bluetooth passkey was not set properly and therefore it was denying access to the serial port.
Just replace your COM# with \.\COM# in your code,
hComm = CreateFile("\\\\.\\COM15",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
0,
0);

Resources