I'm trying to read serial data from an Arduino to my Mac (10.12.6). I have downloaded the Synapse library for FreePascal (Lazarus v.2.0.8) from here but I run into an error...
The Arduino is programmed using the Arduino IDE and sends random numbers (between 0 and 255) as a string to the serial port. I am trying to read these strings using FreePascal so that I can plot the values.
Following instructions here I have downloaded and used the Synapse library in the following way:
1) Uncompress the library folder
2) In Lazarus goto 'Project' -> 'Project Inspector' -> 'Add Files from File System' -> select 'synaser.pas'.
3) Add the following code to the form button event:
procedure TForm1.Button1Click(Sender: TObject);
var
ser: TBlockSerial;
begin
ser := TBlockSerial.Create;
try
ser.Connect('my-com-port'); // write here Arduino COM port number (on linux it's something like '/dev/ttyUSB0')
Sleep(250);
ser.config(9600, 8, 'N', SB1, False, False);
ser.SendString('on'); // button 2 should have 'off' here
finally
ser.free;
end;
end;
4) Press run.
An error message appears in the synaser.pas file:
Error incompatible types: got "ShortInt" expected "Pointer"..
Here's the part of the synaser.pas file referred to:
{$IFNDEF MSWINDOWS}
procedure TBlockSerial.Purge;
begin
{$IFNDEF FPC}
SerialCheck(ioctl(FHandle, TCFLSH, TCIOFLUSH));
{$ELSE}
{$IFDEF DARWIN}
SerialCheck(fpioctl(FHandle, TCIOflush, TCIOFLUSH)); { <------ here*******}
{$ELSE}
SerialCheck(fpioctl(FHandle, TCFLSH, Pointer(PtrInt(TCIOFLUSH))));
{$ENDIF}
{$ENDIF}
FBuffer := '';
ExceptCheck;
end;
I am using a Mac and this error seems to be related to a windows system?
Thanks #tonypdmtr.
I had to change the 'synaser.pas' file in the following way to get it to work. Bit of a hack I feel:
Change line 1939 to the following:
SerialCheck(fpioctl(FHandle, TCIOflush, Pointer(PtrInt(TCIOFLUSH))));
Comment out lines 2201, 2202 and 2204 in the same. This sounds like a bad way of doing it but I got it to work.
Changing the button event to the following code allows me to read a single line of data from the Arduino with each button click:
procedure TForm1.Button1Click(Sender: TObject);
var
ser: TBlockSerial;
begin
ser := TBlockSerial.Create;
try
ser.Connect('/dev/cu.wchusbserial1420'); // write here Arduino COM port number (on linux it's something like '/dev/ttyUSB0')
Sleep(250);
ser.config(9600, 8, 'N', SB1, False, False);
Label1.Caption := ser.RecvString(100);
finally
ser.free;
end;
end;
I feel the library should just work without having to change it.
Related
I'm trying to get the data stream of a sensor transmitter that uses the modbus rtu communication protocol on my raspberry pi 3B. I'm able to get the data with the pymodbus2.5.3 library.
For this I use this code:
from pymodbus.client.sync import ModbusSerialClient # Import the pymodbus library part for syncronous master (=client)
client = ModbusSerialClient(
method='rtu', #Modbus Modus = RTU = via USB & RS485
port='/dev/ttyUSB0', #Connected over ttyUSB0, not AMA0
baudrate=19200, #Baudrate was changed from 38400 to 19200
timeout=3, #
parity='N', #Parity = None
stopbits=2, #Bites was changed from 1 to 2
bytesize=8 #
)
if client.connect(): # Trying to connect to Modbus Server/Slave
#Reading from a holding register
res = client.read_holding_registers(address=100, count=8, unit=1) #Startregister = 100, Registers to be read = 8, Answer size = 1 byte
if not res.isError(): #If Registers don't show Error
print(res.registers) #Print content of registers
else:
print(res) #Print Error Message, for meaning look at (insert git hub)
else: #If not able to connect, do this
print('Cannot connect to the Transmitter M80 SM and Sensor InPro 5000i.')
print('Please check the following things:')
print('Does the RS485-to-USB Adapter have power? Which LEDs are active?')
print('Are the cables connected correctly?')
And get the following output:
[15872, 17996, 16828, 15728, 16283, 45436, 16355, 63231]
With the help of the Modbus Poll and Slave Programms I know that those results should decoded be:
[0.125268, --, 23.53, --, 1.21094, --, 1.77344, --]
To get to the right results I tried the command that the pymodbus github suggests .decode():
res.decode(word_order = little, byte_order = little, formatters = float64)
[I know that those aren't the needed options but I copied the suggested github code to check if it works.]
After putting the code segment into the code the changed part looks like this:
if not res.isError(): #If Registers don't show Error
res.decode(word_order = little, byte_order = little, formatters = float64)
print(res.registers) #Print content of registers
else:
print(res) #Print Error Message, for meaning look at (insert git hub)
When I run this code, I get the following output, that traces to the decoding segment:
NameError: name 'little' is not defined
After this, I imported also the pymodbus part translation. But it showed the same output.
How can I decode my incoming data?
You can use BinaryPayloadDecoder to help decoding your payload, here is a simplified example, change Endian.Big and Endian.Little if needed.
if client.connect(): # Trying to connect to Modbus Server/Slave
#Reading from a holding register
res = client.read_holding_registers(address=100, count=8, unit=1) #Startregister = 100, Registers to be read = 8, Answer size = 1 byte
# ====== added code start ======
decoder = BinaryPayloadDecoder.fromRegisters(res.registers, Endian.Little, wordorder=Endian.Little)
first_reading = decoder.decode_32bit_float()
second_reading = decoder.decode_32bit_float()
# ====== added code end ======
if not res.isError(): #If Registers don't show Error
print(res.registers) #Print content of registers
else:
print(res) #Print Error Message, for meaning look at (insert git hub)
Remember to import from pymodbus.payload import BinaryPayloadDecoder at top and add necessary exception handlers in your final code.
Reference document: https://pymodbus.readthedocs.io/en/latest/source/library/pymodbus.html#pymodbus.payload.BinaryPayloadDecoder
I'm trying to build up an installer using Inno Setup. I need to setup a prerequisite installation for .NET Core framework. By far I'm able to detect .NET Core existence. But I'm having difficulty with executing the installation.
Here's the code I have by far:
[Files]
Source: "\\shared\path\dotnet-runtime-3.1.10-win-x64.exe"; DestDir: "{tmp}"; \
Flags: deleteafterinstall; BeforeInstall: InstallFramework; \
Check: FrameworkIsNotInstalled
[Code]
var
CancelWithoutPrompt: boolean;
InstallValue: Cardinal;
function InitializeSetup(): Boolean;
begin
CancelWithoutPrompt := false;
result := true;
end;
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
if CurPageID=wpInstalling then
Confirm := not CancelWithoutPrompt;
end;
function FrameworkIsNotInstalled: Boolean;
begin
Result := not RegQueryDWordValue(HKEY_LOCAL_MACHINE,
'SOFTWARE\WOW6432Node\dotnet\Setup\InstalledVersions\x64\sharedfx\Microsoft.NETCore.App',
'3.1.10', InstallValue) or (InstallValue <> 1)
end;
procedure InstallFramework;
var
StatusText: string;
ResultCode: Integer;
begin
StatusText := WizardForm.StatusLabel.Caption;
WizardForm.StatusLabel.Caption := 'Installing .net core framework...';
WizardForm.ProgressGauge.Style := npbstMarquee;
try
if not Exec(ExpandConstant('{tmp}\dotnet-runtime-3.1.10-win-x64.exe'), '/q /norestart', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
// you can interact with the user that the installation failed
MsgBox('.NET Core installation failed with code: ' + IntToStr(ResultCode) + '.',
mbError, MB_OK);
CancelWithoutPrompt := true;
WizardForm.Close;
end;
finally
WizardForm.StatusLabel.Caption := StatusText;
WizardForm.ProgressGauge.Style := npbstNormal;
end;
end;
I'm getting result code 2 response from the installation, anyone could enlighten me what's code 2 error about? Or is that any way I could extract further detail on the error information? I tried empty argument and tried to search for Code 2 error information on the internet but still no luck.
I had tried with Shellexec and both return the same result
The installation directly using the .net exe are working fine locally
Any help or information would be much appreciate =)
You are trying to run the dotnet-runtime-3.1.10-win-x64.exe before you actually "install" it to the {tmp}:
BeforeInstall: InstallFramework
You have to use the AfterInstall parameter:
AfterInstall: InstallFramework
I want to write and build and execute a Pascal Program in Notepad ++. If i execute the program in cmd the output is normal, but in the console in nppexec the output is empty
My Code:
Program Edgar;
Uses Crt;
Var cnt, tip, pot : INTEGER;
Begin
TextColor(Red);
WriteLn('Hallo');
tip := -1;
cnt := 0;
Randomize;
pot := Random(2501)*10;
WriteLn(pot);
WHILE (tip <> pot) do
Begin
WriteLn('Tip: ');
ReadLn(tip);
if (tip < pot) then begin
WriteLn('Too low');
cnt := cnt + 1
end;
if (tip > pot) then begin
WriteLn('Too High');
cnt := cnt + 1
end;
end;
cnt:= cnt + 1;
WriteLn('IA IA');
WriteLn('Tries: ',cnt );
End.
Build Commands:
cd $(CURRENT_DIRECTORY)
fpc $(NAME_PART).pas
$(NAME_PART).exe
Output(Nppexec):
Free Pascal Compiler version 2.6.2 [2013/02/12]
for i386 Copyright (c) 1993-2012 by Florian Klaempfl
and others Target OS: Win32 for i386
Compiling ue23.pas
Linking ue23.exe 27 lines compiled, 0.1 sec , 33536 bytes code, 1900 bytes data
<<< Process finished.
(Exit code 0)
ue23.exe Process started >>>
If you enable unit CRT, the application will write to the console directly (using *console winapi functions) instead of using stdout.
Probably the console screen of npp is not a real console screen, but a capture of stdout (-piped) only.
Except not using crt (and thus not using cursor movement and coloring) there is not much that can be done, this is probably a NPP limitation.
After that, you need to press "Enter" while your cursor blinking in output side.
And you will get the output with these lines at the end.
<<< Process finished. (Exit code 0)
================ READY ================
There is no limitation, you can run commands from that output side of notepad++.
My Inno Script installer makes an empty folder in the C: drive but only on one machine. Every other machine I've tested the script on works without this problem. I've tested on two Windows 7 computers, an XP computer and a Windows XP virtual computer. For all of these computers the installer doesn't create this empty folder.
However, on my colleague's Windows XP computer the installer behaves as it should except that it also creates an empty directory on the C Drive. Uninstalling does not remove the folder.
I've had a look through my script and looked for things that could possibly be creating the extra folder, but I can't see anything. It's especially hard to solve because I can't seem to replicate the problem.
Does anyone here have an idea of why this could be happening?
#define MyAppName "Program1"
#define MyAppVersion "1.0"
#define MyAppExeName "program1.exe"
[Setup]
AppName=Test
AppVersion=1.0
AppPublisher=Me
AppSupportURL=www.google.com
AppUpdatesURL= www.google.com
DefaultDirName={code:getDirectory}
UsePreviousAppDir=no
DisableDirPage=yes
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
OutputBaseFilename={#MyAppName} {#MyAppVersion} Setup
Compression=lzma
SolidCompression=yes
OutputDir=output
UninstallFilesDir={code:getDirectory}
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
[Files]
Source: "test.iss"; DestDir: "{code:getDirectory}"; Flags: ignoreversion;
[Code]
var
InstallTestVersionCheckBox: TNewCheckBox;
Directory : string;
// ------------------------------
// INSTALL
// ------------------------------
procedure InitializeWizard;
var
MainPage: TWizardPage;
begin
MainPage := CreateCustomPage(wpWelcome, 'text', 'text');
// make the checkbox
InstallTestVersionCheckBox := TNewCheckBox.Create(MainPage);
InstallTestVersionCheckBox.Parent := MainPage.Surface;
InstallTestVersionCheckBox.Caption := 'Test Version';
end;
function InstallTestVersion: Boolean;
begin
Result := InstallTestVersionCheckBox.Checked;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if InstallTestVersion() then
begin
// Set the test version directory
Directory := ExpandConstant('{pf32}\Testversion');
end
else
begin
// Set the production version directory
Directory := ExpandConstant('{pf32}\Normal');
end;
end;
// Returns the correct directory
function getDirectory(Param: String): String;
begin
Result := Directory;
end;
For those who might run into similar problems: Inno setup suddenly created additional empty folders I didn't want to have. Finally I understood the reason: I tried to create a single empty folder within the [Files] section. That was no good idea... So you just create your empty folder with the [Dirs] section to do it the good way.
DO NOT DO THIS:
[Files]
Source: "M:\My_Empty_Folder"; DestDir: "{userdocs}\My_App_Name"; Flags: ignoreversion
THIS IS BETTER:
[Dirs]
Name: "{userdocs}\My_App_Name\My_Empty_Folder"
I wrote simple pro*c program to check database connectivity. The code is :
int main()
{
char *conn_string = "IDA/IDA#DBISPSS";
int x = 10;
printf("value of x is before db connection %d\n",x);
printf(" conn_string %s \n",conn_string);
EXEC SQL CONNECT :conn_string;
EXEC SQL SELECT 1 INTO :x FROM DUAL;
printf("value of x is %d\n",x);
return 0;
}
Following commands I executed to create exectuable (test_connection) of pro*c code
proc test_connection.pc
cc -I${ORACLE_HOME}/precomp/public -c test_connection.c
cc test_connection.o -o test_connection -L$ORACLE_HOME/lib -lclntsh
and when I executed test_connection exe,the output is
value of x is before db connection 10
conn_string IDA/IDA#DBISPSS
Segmentation fault
But the same code workes well in another linux machine and solaris machine.
Why segmentation fault is thrown?
I tested in HPUX 11.11/Oracle 11 and work ok. I don't see any problem, but try some changes:
Declare 'x' into a DECLARE SECTION:
EXEC SQL BEGIN DECLARE SECTION;
int x = 0;
EXEC SQL END DECLARE SECTION;
Try this connection command:
EXEC SQL BEGIN DECLARE SECTION;
char *user = "abc", *password = "123", *database="base";
EXEC SQL END DECLARE SECTION;
EXEC SQL DECLARE BASE_HANDLE DATABASE;
...
EXEC SQL CONNECT :user IDENTIFIED BY :password AT BASE_HANDLE USING :database;
...
EXEC SQL AT BASE_HANDLE SELECT 1...
Insert a printf("here 1"); between EXEC SQL CONNECT... and EXEC SQL SELECT ... to see where SEGFAULT is thrown.
I had that problem and no amount of fiddling with my source made any difference. What finally worked was when I reinitialized all (ALL) my libraries to make sure that Oracle only had access to the 32 bit versions of the library. It seems Oracle was somehow getting connected to a 64 bit library. Only by removing all references to any libraries or executables except the 32 bit versions worked. This included running a 32 bit version of Pro*C.