Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

PSoC™ 5, 3 & 1

Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

I'm making improvements to my custom Term component.

I've got a modest work-around to determine if the host port is open.  I'd like to improve upon that.  

The goal:  Quickly determine if the Host port is open and ready to comm or if the host port is closed and DO NOT try to transmit.

Note: USBUART_CDCIsReady() will not work in this instance since it will always return 'not ready' if the Tx buffer is full OR if the HOST port is NOT opened.

I've gone through the datasheet, the USBUART component source code, and made some experimental code.  All to no luck.

Is there an API or Global variable that indicates whether the Host port is open?

Thanks in advance for your help and suggestions.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
1 Solution
Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

Rodolfo,

In my case, I never get the USBUART_wValueLoReg = 0 for some reason. Your results do make more sense.


According to what I have read the USBUART_wValueLoReg in this request is suppose to contain the flow control signaling bits from the host.  Only DTR and RTS are defined for now with '0' being "No Flow Control".


Another thing I noticed is that when I closed the port, there are two requests to update the lineControlBitmap[], while when opening the port, there is only one. Also, when opening the port, it does have some additional requests to read/write.


The multiple requests are not unusual.   It's host dependant.

My own terminal program sends out about 4 to 5 requests (I should check into that).  

I also use Termite.  It sends out two requests. (Termite has "None, DTR and RTS" flow settings).

I also use the default Windows 10 terminal host program called "Terminal".  It has NO flow control and is extremely simple.   It only sends one request.


As I mentioned before, I think you can create a state machine to track the sequence of actions on the dispatcher, so it could eventually move from one state to other. It could have four states:

- Port is open

- Opening port

- Closing port

- Port is closed


I want to detect one of three conditions:

  • Port Opened
  • Port Closed
  • USB comm active.  (Cable connected)

I can detect USB comm active is detected by the presence of a 1ms SOF pulse.  This is easily supported with enabling the SOF ISR.  If I miss 3 pulses, I can assume the port is closed.

 I have studied the PSTN V1.2 of the USB CDC spec.  Using this protocol, I have not conclusively detected a signal being passed from the host to device to indicate port open or port close at the host side. 

 

 

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

0 Likes
16 Replies
RodolfoGL
Employee
250 sign-ins 5 comments on KBA First comment on KBA
Employee

Usually when a terminal software tool opens a COM port, it sends the port settings. You can try to leverage that. In the USBUART_cdc.c file, there is a function called USBUART_DispatchCDCClassRqst(). It has hooks to include callbacks on write requests.

You might add your code in here:

/* `#START CDC_WRITE_REQUESTS` Place other request handler here */

/* `#END` */

0 Likes
Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

Rodolfo,

Thank you for interest in this topic and for your suggestion.

In actuality, I can reliably detect a host port 'open' and I can can reliably detect if the cable is disconnected.

What I'm having trouble with is if the user closes the host port

I'm aware of the USBUART_DispatchCDCClassRqst() function.  I've reviewed the function with no luck in finding a "host port close" routine.

If you're aware of one I would be thankful.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
RodolfoGL
Employee
250 sign-ins 5 comments on KBA First comment on KBA
Employee

Doing a quick experiment, I notice that the USBUART_CDC_SET_CONTROL_LINE_STATE is set with bitmap to 0x0002 every time the host closes the port.

So if you want to detect such event, set a flag when:

UBBUART_bRequestReg == USBUART_CDC_SET_CONTROL_LINE_STATE &&  USBUART_lineControlBitmap[comPort] == 0x0002

0 Likes
Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

Rodolfo,

I've looked at Term_USBUART_DispatchCDCClassRqst()

(USBUART_bRequestReg == USBUART_CDC_SET_CONTROL_LINE_STATE)

If the Request == USBUART_CDC_SET_CONTROL_LINE_STATE then the data in the  USBUART_wValueLoReg is either:

  • USBUART_LINE_CONTROL_DTR
  • USBUART_LINE_CONTROL_RTS
  • RESERVED

USBUART_wValueLoReg  value gets set in the USBUART_lineControlBitmap[comPort].

When  (USBUART_lineControlBitmap[comPort] == 0x02) then USBUART_LINE_CONTROL_RTS is true.

When the port closes  USBUART_lineControlBitmap[comPort] gets set to 0. (ie USBUART_LINE_CONTROL_DTR and USBUART_LINE_CONTROL_RTS are false even if previously true.)

I looked at using the (USBUART_lineControlBitmap[comPort] == 0x00) as a port closed indicator.  The issue is that if the Flow control on the Host terminal program uses "NONE", then (USBUART_lineControlBitmap[comPort] ALWAYS == 0.  Essentially this is not going to work with most Host Terminal programs.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
RodolfoGL
Employee
250 sign-ins 5 comments on KBA First comment on KBA
Employee

I used TeraTerm and Putty.

In both cases, when I closed the port, the USBUART_wValueLoReg is set to 0x02. Whatever I set in the FlowControl, the USBUART_wValueLoReg is always set to 0x03.

However,  I do read this in the comments of USBUART_GetLineControl:

* *Note* Some terminal emulation programs do not properly handle these
* control signals. They update information about DTR and RTS state only
* when the RTS signal changes the state.

Still, I think you can leverage this. To differ between setting  the FlowControl and Disconnecting, I believe the terminal host will send some additional commands to change the FlowControl. While Disconnecting only change the lineControlBitmap. You could keep an internal state machine to track what's going on the Dispatcher.

0 Likes
Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

Rodolfo,

Again. Thank you for your interest in this topic.

In TeraTerm and Putty what do you get in USBUART_wValueLoReg when Flow Control = None.

Here are my results with USBUART_wValueLoReg (Addr = 0x40006002) :

Using Host DTR flow control:

  • Port open: USBUART_wValueLoReg == USBUART_LINE_CONTROL_DTR == 0x01.
  • Port close: USBUART_wValueLoReg == 0x00.

Using Host RTS flow control:

  • Port open: USBUART_wValueLoReg == USBUART_LINE_CONTROL_RTS == 0x02. (when implemented properly at the host)
  • Port close: USBUART_wValueLoReg == 0x00.

Using Host None flow control:

  • Port open: USBUART_wValueLoReg == 0x00.
  • Port close: USBUART_wValueLoReg == 0x00.

This is monitored in Term_USBUART_DispatchCDCClassRqst()  line 201.

You can see from my results, this register is ALWAYS 0x00 whether open or closed when Flow control is NONE.

For your results, where are you monitoring this register?

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
RodolfoGL
Employee
250 sign-ins 5 comments on KBA First comment on KBA
Employee

In my case, I never get the USBUART_wValueLoReg = 0 for some reason. Your results do make more sense.

Another thing I noticed is that when I closed the port, there are two requests to update the lineControlBitmap[], while when opening the port, there is only one. Also, when opening the port, it does have some additional requests to read/write.

As I mentioned before, I think you can create a state machine to track the sequence of actions on the dispatcher, so it could eventually move from one state to other. It could have four states:

- Port is open

- Opening port

- Closing port

- Port is closed

0 Likes
Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

Rodolfo,

In my case, I never get the USBUART_wValueLoReg = 0 for some reason. Your results do make more sense.


According to what I have read the USBUART_wValueLoReg in this request is suppose to contain the flow control signaling bits from the host.  Only DTR and RTS are defined for now with '0' being "No Flow Control".


Another thing I noticed is that when I closed the port, there are two requests to update the lineControlBitmap[], while when opening the port, there is only one. Also, when opening the port, it does have some additional requests to read/write.


The multiple requests are not unusual.   It's host dependant.

My own terminal program sends out about 4 to 5 requests (I should check into that).  

I also use Termite.  It sends out two requests. (Termite has "None, DTR and RTS" flow settings).

I also use the default Windows 10 terminal host program called "Terminal".  It has NO flow control and is extremely simple.   It only sends one request.


As I mentioned before, I think you can create a state machine to track the sequence of actions on the dispatcher, so it could eventually move from one state to other. It could have four states:

- Port is open

- Opening port

- Closing port

- Port is closed


I want to detect one of three conditions:

  • Port Opened
  • Port Closed
  • USB comm active.  (Cable connected)

I can detect USB comm active is detected by the presence of a 1ms SOF pulse.  This is easily supported with enabling the SOF ISR.  If I miss 3 pulses, I can assume the port is closed.

 I have studied the PSTN V1.2 of the USB CDC spec.  Using this protocol, I have not conclusively detected a signal being passed from the host to device to indicate port open or port close at the host side. 

 

 

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
WaMa_286156
Level 5
100 replies posted 50 replies posted 50 questions asked
Level 5

Not sure if this is what you were asking, but this pattern allowed me to resend strings on disconnect/reconnect:

/* Host can send double SET_INTERFACE request. */
if (0u != USBUART_IsConfigurationChanged())
{
/* Initialize IN endpoints when device is configured. */
if (0u != USBUART_GetConfiguration())
{
/* Enumeration is done, enable OUT endpoint to receive data
* from host. */
USBUART_CDC_Init();
}
}
 
if(0 != USBUART_GetConfiguration()){
     if (USBUART_IsLineChanged())
          firstTime = pdTRUE;
 
if (firstTime){
     // every time a connect or change of baud, etc. occurs
    // print the signon string
    firstTime = pdFALSE;
    // USBport_putString(START_STRING CRLF);
}
}
0 Likes
Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

WaMa,

Thank you for your input.

I'm trying to, in effect, emulate a standard UART port with the USBUART.   

The standard UART will transmit data on the Tx line even if the host-side port is not open.

In my case, when I need to send data from the PSoC and the host port is not open, I WANT the data to be lost.  I don't want it to queue the data until the port opens.

With the USBUART, the PutString(), PutChar() and PutArray() functions will block indefinitely if the host port is not open.  This is not like the standard UART for the same functions and is not desirable in my case.

For example: I create applications that continuously "do things".  It is also advantageous to dump some diagnostic information to a host comm port while it is "doing things".  However, thing are many times when I since need to "do things" and let the diagnostic info dump "into the ether" with the host port is closed.

Importantly, I don't want the  "doing things" to stop or even "hiccup" in it operation.  With the USBUART component, the PutString(), PutChar() and PutArray() functions I use to dump the diagnostic data halts the "doing things" because these are blocking functions and the host port is closed.

In short, my Term Component can reliably detect when the host port first opens.  However, it cannot reliably detect when the host port closes.   This is the reason for this thread.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
WaMa_286156
Level 5
100 replies posted 50 replies posted 50 questions asked
Level 5

I guess the IsLineChanged() function might work for you.  Or whatever is below it.

I suspect you need a timer based interrupt that monitors the items you have identified and can set flags.  Rewrite the Put_String(), etc. routines and call them instead.  Monitor your flag(s) or indicators in those routines and swallow the data being sent.  Is a lot of work for this effect, and may only help you in your code.

OR

You can insanely step on the monitoring code and give it false information from the ISR in place.  not easy to do, and only works for 1 version of code.

OR

Have your code create fake registers in RAM and make them a copy of the registers from the hardware, being fed by a timer based  isr. (1 millisecond timer, perhaps)  Fake out an alive connection even when the connection is dead due to disconnect.  You could do that with well place #defines and leave original code mostly alone.

A fast ISR running 1000 times per second is not a load on a 24mhz cpu. (or less at higher speeds).  9600 baud is 1 character per millisecond, so it would not "stall" things much.

A bit dangerous

 

0 Likes
Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

WaMa,

As you can see from your design concept "thought experiments", it is easy.

BTW.  I thought about using IsLineChanged().  It works very well if the DTR/DSR functionality is used on the host end.  When the host opens the port it asserts DTR.  When the host closes that port it de-asserts DTR.

This can be easily detectable.

The problem is if NO HW flow control is used on the host, there is NO DTR.  In this case, when the host opens the port DTR == 0.   When the host closes the port DTR == 0.

My host terminal program uses DTR.  However MANY host terminal programs have NO HW flow control.  I'm tryin to accommodate ALL terminal programs if I can.

From what I can tell from reading the USB CDC version 1.2 spec, there is no guaranteed signal  (using EP0) to/from the host to acquire port status or to ask about the host port status.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
WaMa_286156
Level 5
100 replies posted 50 replies posted 50 questions asked
Level 5

Hmm.  In that case, the "shadow" registers in RAM would probably work.  The PutString() function would write merrily away thinking the fifo is never full.

 

0 Likes
Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

WaMa,

The USUART has no RAM "shadow" registers that I'm aware of.

The USUART by default allocates 64 bytes of RAM as a temporary buffer for the Device-to-Host sending End-point.  

The issue is that the USBUART PutString() function is monitoring part of the low-level USB protocol to determine if the current set of data has been sent.  If the Host port is closed, the function 'hangs' indefinitely.   This is the "problem" I'm trying to solve.

If I get knowledge from the host that the port is closed, I can reliably know to "throw away" the Tx data before executing the PutString() function.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
WaMa_286156
Level 5
100 replies posted 50 replies posted 50 questions asked
Level 5

I apologize!  My thoughts were not made clear.  I suggest you make your own "shadow" register.

Create a clock and feed an ISR.  That clock will run at whatever rate you decide is good enough to handle your situation.  For me, 1000 hertz is a good rate, it produces one interrupt per millisecond.  Very fast in terms of plugging and unplugging USB connectors, or programs going away.

In that ISR, look at the register(s) for the USB device and copy them to a global RAM variable after you modify the information to meet your needs.  That RAM copy then becomes a "shadow" register, as it reflects the USB register in close to real-time, but it has the changes you need.

Unfortunately, the Cypress code may make that too difficult.  If you can grab the Cypress code and re-write it slightly, and use it in your code instead, you may be able to get around this.  A lot of times I will grab the Cypress code and in their possibly infinite loops, watch my system millisecond counter.  If too much time has elapsed, I consider the port dead and bail.  This is where I usually put a "watcher" to bail from the loop:

            /* Wait until host read data from IN endpoint buffer. */

            while (USBUART_IN_BUFFER_FULL == USBUART_EP[epNumber].apiEpState)

            {

              // psueudo code

                    if (elapsedTime>xx_millseconds)

                       break;

            }

 

Good luck!

 

0 Likes
Len_CONSULTRON
Level 9
1000 replies posted 750 replies posted 500 likes received
Level 9

WaMa,

I'm considering your suggestion.

The 1ms loop is easy.  The USBUART has a 1ms SOF ISR naturally as part o the system.  The SOF is received by the USB port on the host being opened.   Sadly, this cannot be used for the CDC UART virtual port open/closed signal.

If I use it as my timing ISR, I get the added benefit that if I stop getting the SOF ISR is because I had a "hard" port close.  Ie.  The USB cable was disconnected.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes