JSSC Serial connection and its flow control - serial-port

I need to send a long text to serial printer using Jssc library. After a few I get a full buffer error, so I thought it can be the flow control settings, because for smaller transmission everything works.
The printer can use XON/XOFF flow control configuration or CTS/RTS hardware signals.
SOFTWARE FLOW CONTROL
My jssc code to open the port is this:
serialPort.openPort();
serialPort.setParams(baud, data, stop, SerialPort.PARITY_NONE);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_XONXOFF_IN | SerialPort.FLOWCONTROL_XONXOFF_OUT);
This works only for a small text output, for longer output the printer throw a full buffer error.
HARDWARE FLOW CONTROL
I also try to switch printer to cts/rts flow control and change my code to this:
serialPort.openPort();
serialPort.setParams(baud, data, stop, SerialPort.PARITY_NONE, true, false);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN | SerialPort.FLOWCONTROL_RTSCTS_OUT);
But nothing changes. I still get the buffer error for long output.
Than I check with a COM monitor if my printer correctly sends XOFF chars or CTS signal before filling its buffer and it well works!
At the end I tried to manually manage the output stream stopping it while CTS signal is off (using an event handler) in this way everything works also with long output.... but this is not what the flowcontrol should do automatically?
MANUAL HARDWARE FLOW CONTROL TEST
This is my manual hardware flow control test.
It uses canSend boolean var to control the output stream.
private boolean canSend=true;
public void openPort(
serialPort.openPort();
serialPort.setParams(baud, data, stop, SerialPort.PARITY_NONE, true, false);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
serialPort.addEventListener(new SerialPortReader(), SerialPort.MASK_CTS);
canSend=true;
}
public void write(byte[] content) throws Exception {
ByteArrayInputStream b= new ByteArrayInputStream (content);
byte[] bytes =new byte[OUT_BUFFER_SIZE];
int byteread=0;
while ((byteread=b.read(bytes, 0, bytes.length)) >= 0) {
if(byteread>0){
while(!canSend){
Thread.sleep(CTS_WAIT);
}
if(byteread<bytes.length){
byte[] tocopy=new byte[byteread];
System.arraycopy(bytes, 0, tocopy, 0, byteread);
serialPort.writeBytes(tocopy);
}else{
serialPort.writeBytes(bytes);
}
}
}
}
private class SerialPortReader implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
if(event.isCTS()){
canSend=event.getEventValue() == 1;
}
}
}
Seems that the flowcontrol settings is completely ignored.
What can be? Is it a jssc error a windows driver error?
I also tries to check it with getFlowControlMode() and I correctly get a values of 3 for the hardware flow control test.

At the end the problems was not the jssc library but usb to serial adapter. Changing it with a FTDI chip based adapter it works. (Moreover seems that also the last driver's release of Prolific adapter works).

Related

Microsoft's MPEG-2 demuxer filter - can I change an elementary stream pin's PID while the graph is running?

I'm working with multi-program UDP MPEG-2 TS streams that, -unfortunately- dynamically re-map their elementary stream PIDs at random intervals. The stream is being demuxed using Microsoft's MPEG-2 demultiplexer filter.
I'm using the PSI-Parser filter (an example filter included in the DirectShow base classes) in order to react to the PAT/PMT changes.
The code is properly reacting to the change, yet I am experiencing some odd crashes (heap memory corruption) right after I remap the Demuxer pins to their new ID's. (The re-mapping is performed inside the thread that is processing graph events, while the EC_PROGRAMCHANGED message is being processed).
The crash could be due to faulty code in my part, yet I have not found any reference that tells me if changing the pin PID mapping is safe while the graph is running.
Can anyone provide some info if this is operation is safe, and if it is not, what could I do to minimize capture disruption?
I managed to find the source code for a Windows CE version of the demuxer filter. Inspecting it, indeed, it seems that it is safe to remap a pin while the filter is running.
I also managed to find the source of my problems with the PSI-Parser filter.
When a new transport stream is detected, or the PAT version changes, the PAT is flushed, (all programs are removed, the table is re-parsed and repopulated).
There is a subtle bug within the CPATProcessor::flush() method.
//
// flush
//
// flush an array of struct: m_mpeg2_program[];
// and unmap all PMT_PIDs pids, except one: PAT
BOOL CPATProcessor::flush()
{
BOOL bResult = TRUE;
bResult = m_pPrograms->free_programs(); // CPrograms::free_programs() call
if(bResult == FALSE)
return bResult;
bResult = UnmapPmtPid();
return bResult;
}// flush
Here's the CPrograms::free_programs() implementation.
_inline BOOL free_programs()
{
for(int i= 0; i<m_ProgramCount; i++){
if(!HeapFree(GetProcessHeap(), 0, (LPVOID) m_programs[i] ))
return FALSE;
}
return TRUE;
}
The problem here is that the m_ProgramCount member is never cleared. So, -apart from reporting the wrong number of programs in the table after a flush (since it is updated incrementally for each program found in the table)-, the next time the table is flushed, it will try to release memory that was already released.
Here's my updated version that fixes the heap corruption errors:
_inline BOOL free_programs()
{
for(int i= 0; i<m_ProgramCount; i++){
if(!HeapFree(GetProcessHeap(), 0, (LPVOID) m_programs[i] ))
return FALSE;
}
m_ProgramCount = 0; // This was missing, next call will try to free memory twice
return TRUE;
}

Write usb bulk windows with winusb

Im trying to send some data using the bulkout endpoint of a usb device.
I can open the usb device (corsair k65rgb keyboard) interface 2 (which control the lighting) using createfile and SetupDiGetDeviceInterfaceDetail.
But the example code I have write data using HidD_SetFeature. And from the usb sniffer it write urb function classe interface (using the control endpoint)
but when I open corsair cue software it use urb function bulk or interrupt transfer.
So I know its possible to send bulk data. But im lost on how to do it
Thank you
I use QT 5.9 and VS2015
You could try the winusb call WinUsb_WritePipe() for transfering data using bulk transfers.
A interface handle is required before we can use WinUsb calls.It is obtained by using setupApi calls and after the required device is found.
Use CreateFile() call to open the file handle and perform WinUsb_Initialise() to obtain the interface handle.
We can use this interface handle for further WinUsb calls.For Bulk transfer we would also require pipe(Endpoint) information which can be obtained by
WinUsb_QueryPipe() call.
Check the following reference for list of winusb calls:
https://learn.microsoft.com/en-us/windows/desktop/api/winusb/
This is an example code for Bulk transfer using a winusb call.
BOOL WriteToBulkEndpoint(WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pID, ULONG* pcbWritten)
{
if (hDeviceHandle==INVALID_HANDLE_VALUE || !pID || !pcbWritten)
{
return FALSE;
}
BOOL bResult = TRUE;
UCHAR szBuffer[] = "Hello World";
ULONG cbSize = strlen(szBuffer);
ULONG cbSent = 0;
bResult = WinUsb_WritePipe(hDeviceHandle, *pID, szBuffer, cbSize, &cbSent, 0);
if(!bResult)
{
goto done;
}
printf("Wrote to pipe %d: %s \nActual data transferred: %d.\n", *pID, szBuffer, cbSent);
*pcbWritten = cbSent;
done:
return bResult;
}
Check the following reference for more details:
Refer:
https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/using-winusb-api-to-communicate-with-a-usb-device
https://learn.microsoft.com/en-us/windows/desktop/api/winusb/nf-winusb-winusb_writepipe

Could I send JSON data with LoRa and how?

I've a SODAQ Mbili board with a LoRa bee. I've also a GPS sensor. Below you could find how I add the bee and the sensor.
On that board I make a JSON string with the GPS coordinates and I'll send that data over the LoRa network. But How could I do that.
In the source code I've download they use next code:
LoRaModemMicrochip modem(&MODEM_SERIAL, &debugSerial);
Device libTest(&modem, &debugSerial);
void readGPSData() {
GPSSensor gpsSens(4.3, 51.222, 15.5, 0);
dumpSendResult(gpsSens);
}
void dumpSendResult(Sensor& sns) {
bool sendResult = libTest.send(sns, true);
}
I'll change this code like code below so I could send my JSON data
LoRaModemMicrochip modem(&MODEM_SERIAL, &debugSerial);
Device libTest(&modem, &debugSerial);
void readGPSData() {
String json = "My JSON code";
dumpJsonResult(json);
}
void dumpJsonResult(String& text) {
bool sendResult = libTest.send(text, true);
}
But it gives me this error:
In function void dumpJsonResult(String&):
Error: no matching function for call to Device::send(String&, bool)
bool sendResult = libTest.send(text, true);
^
Did you know how I could send JSON data to the LoRaWAN?
If you have correct NWSessionKey and APPSessionKey and so on, you could try to onboard your device over Actility's free partner zone.
https://partners.thingpark.com/
Once you do that, you would need to:
Learn how to perform a downlink
Create your own payload mechanism, such as coding your GPS over signed ints for Lat, long and Alt.
Then decode it within your device
Your device could also send ack to an Applicative Server you would plug to Actility's solution (REST-POST/JSON)
Let us know how it goes
Best regards,
What are the libraries used? I haven't found LoRaModemMicrochip object definition on sodaq site.
Have you looked at http://support.sodaq.com/sodaq-one/lorabee/?
I would strongly suggest you to not used JSON with LoRa,as this is very verbose and will use a lot of air time, while the bands where LoRa run have strong duty cycle constrains.

Scanning the serial port periodically to see if the device is connected in QT, QSerialPort

I am trying to scan my serial ports periodically to see if my device is connected or not. Here is what I have done and it works well. I would like to see if there is a better and optimized way to do so.
I created the following timer in my constructor to check the serial port frequently. I made a method (scanSerialPorts()) and call it every 1 second.
QTimer *timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(scanSerialPorts()));
timer->start(1000);
This is my scanSerialPorts() implementation:
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
currentPortName = info.systemLocation();
}
if (currentPortName == "My Desired PortName" ) {
updateSettings();
if ( !serial->isOpen()){
qDebug() << "Serial Not Open";
openSerialPort();
}
} else
{
serial->close();
}
updateSettings(); // Fills up the serial port parameters.
openSerialPort(); //Opens up the serial port.
I used QT examples to write this. Please let me know what you think and how I can make it better.
As it is, you only scan the last port, since the rest of the code is outside the foreachloop;
You close the other (probably not opened) ports instead of the one you're opening
Most probably, availablePorts won't change during execution, so you could move it outside of the scan function to save some processing time in the timer. The same for updateSettings().

How to play QAudioBuffer by QIODevice?

I want to make an audio streaming program (like phone) using the QMediaPlayer, QAudioProbe and QAudioOutput classes in Qt 5.3.0 MSVC2012 OpenGL 32bit.
This is my code:
musicPlayer = new QMediaPlayer();
musicProbe = new QAudioProbe();
musicProbe->setSource(musicPlayer);
connect(musicProbe, SIGNAL(audioBufferProbed(QAudioBuffer)),
this, SLOT(slotGetMusicData(QAudioBuffer)));
If audio data probed, the slot is actived.
void MusicPlayer::slotGetMusicData(QAudioBuffer musicBuffer)
{
/*QAudioBuffer to QByteArray*/
*musicDataBuffer = musicDataBuffer->fromRawData((char *)musicBuffer.data(),
,musicBuffer.byteCount());
/*Send Music Data*/
musicSocket->sendMudicData(*musicDataBuffer);
qDebug("send complete");
}
Using a socket, I send the data to another program.
The other program plays the music received.
QAudioOutput *audioOutput = new QAudioOutput(format, this);
QIoDevice *audioDevice = audioOutput->start();
and then, data received this slot is actived.
void BgmSocket::slotPlayBgm(QByteArray data)
{
audioDevice->write(data.data(), data.size());
}
The audio is playing well, but the sounds have a lot of static (pause sound).
How can I solve this problem?
The problem was a different frequency between the network and the playback buffer.
I solved this problem by creating a buffer with double buffering.

Resources