Recovering from ComPort drop-out - arduino

D5-pro:
Using TurboPower APro and the ComPort and Terminal Components with USB Arduino Nano for a very basic Comms-Terminal. All works fine until I unplug the USB to simulate losing the Port. It all just hangs and will not restart without closing and restarting.
I cannot find an Event or process that is monitoring the Port status so I can gracefully shut the Port. I am able to prevent the Port being opened if it doesn't exist, but once opened and data streaming in, I seem to lose all access to it.
I also tried TComPort and Terminal by Dejan Crnila and it also does not stop gracefully either. It actually crashes and I have to use TaskManager to shut it all down.
Can someone please guide me with some code snippets that might give an indication that the port has gone missing. Or is there a better free Component for doing this.

Some modifications in the AwUser unit are required.
Add a new event for I/O errors.
TPortIOErrorEvent = procedure(CP : TObject; Error : Cardinal) of object;
property OnPortIOError: TPortIOErrorEvent read FOnPortIOError write FOnPortIOError;
Modify the TComThread.Execute method in the AwUser unit.
{Release time slice until we get a communications event}
if not WaitComEvent(CurrentEvent, #ComOL) then begin
if GetLastError = ERROR_IO_PENDING then begin
if GetOverLappedResult(CidEx,
ComOL,
Junk,
True) then begin
{WIN32 bug workaround: Apro gets the modem status bits
with a call (later) to GetCommModemStatus. Unfortunately,
that routine never seems to return either RI or TERI.
So, we note either EV_RING or EV_RINGTE here and later
manually merge the TERI bit into ModemStatus.}
if ((CurrentEvent and EV_RINGTE) <> 0) or
((CurrentEvent and EV_RING) <> 0) then
RingFlag := True;
{Read complete, reset event}
ResetEvent(ComOL.hEvent);
end else begin
{Port closed or other fatal condition, just exit the thread}
SetEvent(GeneralEvent);
CloseHandle(ComOL.hEvent);
H.ThreadGone(Self);
Exit;
end;
end else begin
Err := GetLastError; {!!! added code}
{ If we get an ERROR_INVALID_PARAMETER, we assume it's our }
{ use of ev_RingTe -- clear the flag and try again }
if (GetLastError = ERROR_INVALID_PARAMETER) and
(LastMask and EV_RINGTE <> 0) then begin
LastMask := DefEventMask and not EV_RINGTE;
SetCommMask(CidEx, LastMask);
end;
{!!! added code begin}
if (Err <> ERROR_INVALID_PARAMETER) and (Err>0) and Assigned(FOnPortIOError) then
FOnPortIOError(H.fOwner, Err)
{!!! added code end}
end;
end;
Add the similar code to "ProcessOutputEvent".
In the new event handler analyze the I/O error and close/re-open the port.

Related

running libserialport in any event loop

I am trying to integrate libserialport library to a solution which can use poll, libev and libuv.
while its relatively easy to get the fd for the serial port file from libserialport and watch it using libev or libuv,
uv_poll_init(loop, &poller, serial_port_fd);
uv_poll_start(&poller, UV_READABLE /*| UV_PRIORITIZED*/, cb);
I do not know how to get it working using the default loop using poll.
the main loop is like:
while(!interrupted){
interrupted = service_one_loop();
//// THIS IS ONE PLACE TO poll (serial_port_fd) CODE and call callback function for serial
}
Is there any other way? Something like :
while(!interrupted){
interrupted = service_one_loop();
read_size = sp_nonblocking_read(machine_port, read_buffer, read_buffer_size);
if (read_size >= 0) {
cb();
}
}
Thanks for helping out in advance.

Progress4gl how to lock yourself?

In an unit test, I need to verify that the program skip locked records when processing a table.
I have been unable to setup a locked records because the test can't lock itself which make a lot of sense.
Here is a sample of what I'm trying to achieve.
DEV VAR v_isCommitted AS LOGI NO-UNDO.
DEF VAR hl AS HANDLE NO-UNDO.
DEF BUFFER bufl FOR tablename.
hl = BUFFER bufl:HANDLE.
LOCKED_RECORDS:
DO TRANSACTION ON ERROR UNDO, LEAVE LOCKED_RECORDS:
/*Setup : Create record not committed yet*/
CREATE tablename.
ASSIGN tablename.fields = fieldsvalue.
/*ACT : Code I'm trying to test*/
/*...some code...*/
v_isCommitted = hl:FIND-BY-ROWID(ROWID(tablename), EXCLUSIVE-LOCK, NO-WAIT)
AND AVAILABLE(bufl)
AND NOT LOCKED(bufl).
/*...some code touching the record if it is commited...*/
/*ASSERT : program left new record tablename AS IS.*/
END.
The problem is that the record is available and not locked to the test because it was created by it.
Is there a way I could have the test lock a record from itself so the act part can actually skip the record like it was created by someone else?
Progress: 11.7.1
A session can not lock itself. So you will need to start a second session. For example:
/* code to set things up ... */
/* spawn a sub process to try to lock the record */
os-command silent value( substitute( '_progres -b -db &1 -p lockit.p -param "&2" && > logfile 2>&&1', dbname, "key" )).
In lockit.p use session:parameter to get the key for the record to test (or hard code it I suppose).
Or, as mentioned in the comments below:
/* locktest.p
*/
define variable lockStatus as character no-undo format "x(20)".
find first customer exclusive-lock.
input through value( "_progres /data/sports120/sports120 -b -p ./lockit.p" ).
repeat:
import unformatted lockStatus.
end.
display lockStatus.
and:
/* lockit.p
*/
find first customer exclusive-lock no-wait no-error.
if locked( customer ) then
put "locked".
else
put "not locked".
quit.

watchkit: sleep -- can the isIdleTimer be changed/disabled?

I'm looking for an equivalent to the following iOS option: UIApplication.shared.isIdleTimerDisabled = true
That is, I'd like my Watch application to stay alive longer than the quick "sleep"/idle time that gets triggered when you don't move your wrist.
Its not perfect -- the watch will still sleep with inactvity, but this extension does slow it down by tricking the watch do ignore a 'wrist-down' or 'wrist-move' motion: Add the WKExtension inside one of your #IBActions:
#IBAction func mySlidefunction(){
// ... etc ...
WKExtension.shared().isAutorotating = true;
// ... etc ...
}

FireDac Cached updates stops updating

I am using SQLite databases (Delphi Seattle) FireDac components.
I have more than two applications writing into tables of the same database.
I was getting lock issues therefore started using CachedUpdates and all was fine.
Problem:
At times when the Application is running for more than few hours the Application stops Updating (Edit, Delete) my database tables, Read (Select) works fine.
No error comes up in OnReconcileError. This issue takes place in one of the applications and at the same time the other application using the same database works fine.
If problematic application is restarted, all is well again.
This is how I open my databases
LockingMode=Normal
StringFormat=Unicode
JournalMode=WAL
DriverID=SQLite
SharedCache=False
Synchronous=Full
BusyTimeout=20000
ForeignKeys=Off
Typical pattern of writing
try
wQry:=TFDQuery.Create(Nil);
wQry.Connection:=form_DatabaseWork.FDConnection1 ;
wQry.CachedUpdates:=True ;
wQry.Active:=false;
wQry.sql.text:='Select * from Setups';
wQry.Active:=True;
wQry.Edit ;
wQry.FieldByName('DisplayTitles').AsString:=wMsg ;
ssPost(wQry) ;
ssApplyUpdates(wQry);
finally
wQry.Active:=false;
FreeAndNil(wQry);
end;
Called functions
procedure ssApplyUpdates(pQry:TFDQuery);
var
nErr:Integer ;
begin
nErr:=pQry.ApplyUpdates ;
if nErr>0 then
begin
pQry.OnReconcileError:=form_Tools.Qry_DummyReconcileError ;
pQry.Reconcile ;
pQry.OnReconcileError:=Nil ;
end
else
pQry.CommitUpdates ;
end;
function ssPost(pQry:TFDQuery):Boolean ;
begin
result:=false;
try
pQry.Post;
result:=true;
except
on E: Exception do
WriteSomewhere(E.Message) ;
end;
end;
procedure Tform_Tools.Qry_DummyReconcileError(DataSet: TFDDataSet; E: EFDException; UpdateKind: TFDDatSRowState; var Action: TFDDAptReconcileAction);
begin
Action:=raCorrect ;
end;
I have not added FDconnection.transaction ... Hope that will help. Thanks.

NIO Http file server - connection closed prematurely

I want to create an HTTP static file server using java NIO and it works fine for small files, but seems to truncate the HTTP response for larger files (672 KB out of a 3.8 MB image is returned according to my Chrome Inspector, and my browser displays a a partially corrupted image). Is this code below incorrect?
(I know there are existing libraries for this and eventually I will use one in my project. But initially I want to implement a basic one myself to see if my project concept is feasible.)
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
if (key.isAcceptable()) {
// New Client encountered
serverSocket.accept().configureBlocking(false)
.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// Additional data for existing client encountered
SocketChannel selectedClient = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(548);
String requestedFile2 = getRequstedFile(key, selectedClient, buffer);
buffer.clear();
buffer.flip();
FileChannel fc = FileChannel.open(Paths.get(requestedFile2));
String string = "HTTP/1.1 200 Ok\nContent-Type: image/jpeg\nContent-Length: "
+ (Files.size(Paths.get(requestedFile2)) + "\n\n");
selectedClient.write(ByteBuffer.wrap(string.getBytes()));
while (fc.read(buffer) > -1) {
buffer.flip(); // read from the buffer
selectedClient.write(buffer);
buffer.clear();
}
selectedClient.close();
}
}
(Exception handling etc. omitted for brevity)
EDIT
I have a content-length-mismatch error message. So what is the right way to determine the HTTP response size when reading a file's contents using the NIO API?
buffer.clear();
That should be
buffer.compact();
and the loop should be
while (fc.read(buffer) > 0 || buffer.position() > 0)
You're assuming everything got written by the write.
Also you need to change the HTTP header line terminators to \r\n.
And you need to study RFC 2616 about the content length.
I guess you have to check return value from selectedClient.write(), check the SocketChannel.write() documentation:
Unless otherwise specified, a write operation will return only after writing all of the r requested bytes. Some types of channels, depending upon their state, may write only some of the bytes or possibly none at all.
Which could be the case here. Either add another inner loop which would write to output as long as there are bytes remaining in the buffer. Or you can amend the loop according to example in ByteBuffer.compact(): http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html#compact()
while (buffer.position() > 0 || fc.read(buffer) > 0) {
buffer.flip(); // read from the buffer
selectedClient.write(buffer);
buffer.compact();
}
And remember that the code supposes that selectedClient is blocking. If that wasn't the case, you would need to invoke another select() waiting on the selectedClient becoming writable...

Resources