On Fri, Oct 07, 2011 at 11:00:57PM +0400, Sergey Klimkin wrote:
> >>1
> Multithreading is required for work with serial port, I see no other
> solution.
Another soluttion migh be to run the communication with the device
connected to the serial port in another process, but for what I
understand of you program that might complicate things unneces-
sarily since them you'd need some kind of interprocess communi-
cation (IPC).
> Functions to work with serial port in a separate file and do not cause
> functions xforms.
Then you should be fine;-)
> >>2
> Makefile:
> # compiler
> CC = gcc -Wall
> # target "survey"
> OUTPUT = survey
>
> # create target file "survey"
> (OUTPUT): survey_main.o survey.o survey_cb.o comport.o
> $(CC) survey_main.o survey.o survey_cb.o comport.o -o $(OUTPUT) -lforms
>
> # create obj "survey_main.o"
> survey_main.o: survey_main.c survey.h
> $(CC) -c survey_main.c -o survey_main.o
> # create obj "survey.o"
> survey.o: survey.c survey.h
> $(CC) -c survey.c -o survey.o
> # create obj "survey_cb.o"
> survey_cb.o: survey_cb.c survey.h
> $(CC) -c survey_cb.c -o survey_cb.o
> # create obj "comport.o"
> comport.o: comport.c survey.h
> $(CC) -c comport.c -o comport.o
>
> clean:
> -rm *.o *~ -
>
> In file survey_cb.c
> void cb_btn1( FL_OBJECT * ob,
> long data )
> {
> /* Fill-in code for callback here */
> // Manually add 2 strings - for switch to form/window "FILES" from
> "GNSS_MONITOR"
> fl_hide_form(fd_GNSS_MONITOR->GNSS_MONITOR);
> fl_show_form( fd_FILES->FILES, FL_PLACE_CENTERFREE, FL_FULLBORDER,
> "FILES" );
> }
>
> ... and so on cb_btn2() -- cb_btn6()
>
> terminal:
> sklimkin@sklimkin-desktop:~/projects/fdesign/surveyfd$ make
> gcc -Wall -c survey_cb.c -o survey_cb.o
> survey_cb.c: In function ‘cb_btn1’:
> survey_cb.c:22: error: ‘fd_GNSS_MONITOR’ undeclared (first use in this
> function)
> survey_cb.c:22: error: (Each undeclared identifier is reported only once
> survey_cb.c:22: error: for each function it appears in.)
The variable ‘fd_GNSS_MONITOR’ is a variable local to the main()
function in survey_main.c. One way to avoid that would be to
define it as a global variable in survey_main.c and add a line
like
extern FD_GNSS_MONITOR *fd_GNSS_MONITOR;
to survey_cb.c (or survey.h)
All the other error messages have the same reason, you attempt
to use variables in survey_cb.c that are only defined as local
variables in main() in survey_main.c. After you correct that
everything should compile successfully (at least it did for me).
> Declarations fd_XXXXXX (FD_GNSS_MONITOR *fd_GNSS_MONITOR;) are in
> survey_main.c
What you have in main() in survey_main.c are definitions of those
variables. A "definition" tells the compiler to create a variable
while a declaration merely tells the compiler that a variable is
defined somewhere else and it thus shouldn't worry that it didn't
see a definition.
> in main() - they need to move in survey.h as: static FD_GNSS_MONITOR
> *fd_GNSS_MONITOR;
> otherwise they are invisible to the call from any location.
No, never define variables in heade files! This will result in
each file including the header file getting its own set of the
variables and that's absolutely not what you want. With the
'static' qualifier this still will compile and link without
warnings but the program will not work - each file will have
its own variable of that name, which is completely independent
of the one in another file.
So: always define a variable only once in a .c file and declare
it as far as necessary in a header file or another .c file that
needs access to it (with the 'extern' keyword).
> >>3
> The file exists and the right to read it is. Error in fd-Xforms:
> Objects->Attributes->Spec->button_Browse
> writes the truncated pathy /projects/fdesign/surveyfd/2Garmin_iPAQ.xpm
> but even the full
> path /home/sklimkin/projects/fdesign/surveyfd/2Garmin_iPAQ.xpm
> will be useless when you transfer the program to another machine
> In the file survey.c in the function create_form_GNSS_MONITOR () is a
> line that does not work:
Well, there are some limitations to fdesign - it can't forsee
the future, i.e. where the program will get installed and where
image files are going to be. All it can do is either store the
place where the image file is at the moment you run fdesign -
then you have to make sure that it can be found there when the
program is run (that's why using an absolute path makes a bit
of sense). The alternative is to include the file into your
program (with the "Use Data" button - for xpm files that's an
option since it's nothing but a C array) but in your case the
2Garmin_iPAQ.xpm file is unsuitable since its name results in
a variable name of '2Garmin_iPAQ.xpm' which is not a valid C
variable name since it starts with a digit) and thus compiling
the program with this option will fail).
The simplest solution is probably not to set the file name with
fdesign (that may not look too nice in fdesign, but there are
worse problems;-) and instead set it within the handwritten
part of your program since you're the only one who as any idea
where those image files can be really found. That's at least
how I do it, perhaos someone else here on the mailing list has
some better ideas...
> >>4
> I meant to attach to my e-mail message file with source code, or
> archive-file ZIP-format with an image copy of the screen (as is now
> common at many conferences Internet).
> Here are just now found at the bottom of my Meassage image attached to
> it!
> So you can send Attachment?
Yes, of course, you're sending an email and the mailing list
software can deal quite well with attachments (at least I have
not seen any problems).
On a different topic, not really related to XForms: I also had a
peek at the code for accessing the device connected the serial
device port. And I would like to comment on a few points that
might help you with that part.
I noticed that you open the serial port device file with the
O_NDELAY option (I would consider using O_NONBLOCK). That's
quite fine (and can avoid the open() call to hang). But then
you do things like
BytesRead = read( fd, bRead, BUFSIZE );
if ( BytesRead < 2 )
printf("None answer from Garmin-device. End of connection!\n");
and that could be problematic if the device can't react imme-
diately. In non-blocking mode read() will return just as many
bytes as are available at the moment it is called (even none).
This doesn't necessarily mean that the device is not reacting
or not able to send the data you want but only that not all
you asked for was available at the precise moment read() was
called. The way you do it you might be in for a lot seemingly
not working communications with the device even though the
device is working 100% correct.
There's even a good chance that read() returns -1 because no
data where available at that moment. This is not necessarily
an error. You should check 'errno' for the reason why read()
returned -1. E.g. if 'errno' is 'EAGAIN' the reason was that
no data were available and in that case it's often reasonable
to just try again until some time limit in which the device
should have sent a complete reply has been exceeded.
And even if you had unset O_NONBLOCK read() could return less
bytes than you expected and this would still not necessarily
mean that the device isn't respoding correctly - all you're
guaranteed also in blocking mode is that you will get at least
one byte...
> Probably I don't see the full picture but I don't understand why you
need multithreading.
Fuller picture looks so:
The program is intended for geodesists working in the fields. After
debugging at a workstation it will be transferred on the mobile device
(for example HP iPAQ-214 under control of OS Linux) therefore I am
guided in advance by "slow" processors).
Absence in the program of the menu and very big buttons also are
connected with small display HHPC and work in field conditions.
My weak representation of details of work with external devices through
a serial port and almost full misunderstanding of a multithreading speak
very simply:
1. I not the programmer, I am a geodesist,
2. The previous my programs are written under OS Windows, and there is
only COM1, COM2..., COMn. I didn't reflect on multithreading, as the
environment of working out of the program (Pelles-C) without my
participation has given this possibility.
3. I use only 6 months Linux and only 3 months I try to master
programming (With without pluses) in Linux.
Probably multithreading not the most correct decision, but it that I
have found in examples for libraries GTK+ in Linux.
This method is quite efficient in the program which I have made in
Code-Block with use of libraries GTK+
Now (after very exact remarks Jens) multithreading also works in the
program with libraries xforms.
Program construction in style "server-client communication over the TCP
stack" represents for me interest. But I do not know as it should look.
Therefore, if it does not complicate you, some lines of a code on C-lang
(can be with lines of comments) will be the most clear help.
After connection with the external device (receiver or navigaror) is
established, the program accepts from it and writes down in a file the
continuous binary data flow with a reception interval in 1 second. For
this second it is necessary to execute parsing the accepted data and
still some mathematical transformations and to have time to write down
results in in 3 files (on an accessory of the data).
Practically all GNSS-receivers are arranged so that form the block of
messages and send this block through the fixed interval of time -
usually 1 second. To read from port on 1 byte too slowly. The program
should "see" that the called messages having headings and the
terminations are received. It considerably accelerates the subsequent
data processing.
At this time the user will be switched between program windows that:
1. To establish start and stop for record of each point chosen on
district,
2. To change if it is necessary height of the aerial of the receiver,
3. To look level of signals from visible satellities in a firmament,
4. To look an arrangement of satellities in a firmament.
I represent it as 2 independent problems. Thus an exchange of the
program with the receiver it is desirable anything both not to interrupt
in any way and not to stop at all.
08-10-2011 Terminal-log - example
---------------------------------
sklimkin@sklimkin-desktop:~/projects/fdesign/surveyfd$ ./survey
pixmap_file = /home/sklimkin/projects/fdesign/surveyfd/Garmin_iPAQ.xpm
Function comport() in separated thread is running...
PORTNAME=/dev/ttyS0
USER PORTSPEED=9600
WARNING! Press Ctrl+C to stop program!
16 bytes written to COM-port
Binary file: /home/sklimkin/projects/fdesign/surveyfd/fileout.bin
Bytes readed 537, found Garmin Message 0x33
2 Garmin commands is written!
605 bytes written in file
311 bytes written in file
311 bytes written in file
.. ... ...
312 bytes written in file
Segmentation fault
sklimkin@sklimkin-desktop:~/projects/fdesign/surveyfd$
Depending on the receiver and from quantity of observable satellities,
these lines can be from 300 to 2000 bytes of the binary data.
605 bytes in the first line are 2 packages in the buffer serial-port.
The program has begun dialogue with the receiver in the line:
sleep (2); // in Sec
BytesRead = read(fd, bRead, BUFSIZE);
For a confident finding of the message on that what receiver is
connected to port.
> You can use fl_add_timeout() or fl_add_timer() to invoke the state
machine if the comm. is very lengthy
If it does not complicate you, some lines of a code on C-lang (can be
with lines of comments) will be the most clear help.
> http://www.easysw.com/~mike/serial/serial.html#2_1
Yes it is the good document, thanks.
Sergey Klimkin.
IMHO GNU/Linux systems are amongst the most natural environment where
you can learn programming. I would avoid IDE for programming and stick
to a Makefile and an editor (like Emacs), but it is a choice (FYI Emacs
speedbar is a great tool to navigate through code in case you need).
>
> Probably multithreading not the most correct decision, but it that I
> have found in examples for libraries GTK+ in Linux.
> This method is quite efficient in the program which I have made in
> Code-Block with use of libraries GTK+
> Now (after very exact remarks Jens) multithreading also works in the
> program with libraries xforms.
I find multithreading fascinating, but I would definitely not recommend
that approach if you don't have much of programming experience.
Unfortunately having two threads that are sharing the same memory space
and run "in parallel", may arise a lot of problems when they access the
same resources (as in your case, since one thread is reading/writing
data, while the other is using/producing the data). I'm not an expert in
multithreading programming, but certainly you need to consider shared
memory access, I/O access, task scheduling, synchronization and race
conditions and much more. And bear in mind that multithreading is mostly
done to enhance performances and get the most out of your hardware/OS.
I found this link interesting and maybe helpful for you in case you want
to continue along this path:
https://computing.llnl.gov/tutorials/pthreads/
> Program construction in style "server-client communication over the TCP
> stack" represents for me interest. But I do not know as it should look.
> Therefore, if it does not complicate you, some lines of a code on C-lang
> (can be with lines of comments) will be the most clear help.
I attached two simple programs, a client and a server, which communicate
over tcp. The advantage of this approach is that you need not to worry
about share memory or task scheduling, since it's the OS which does it
for you. In your case the server will perform the access to the serial
port while your client will interact with it.
Again, in principle the server could be multithreaded but I don't think
it is necessary, especially in your application.
>
> After connection with the external device (receiver or navigaror) is
> established, the program accepts from it and writes down in a file the
> continuous binary data flow with a reception interval in 1 second. For
> this second it is necessary to execute parsing the accepted data and
> still some mathematical transformations and to have time to write down
> results in in 3 files (on an accessory of the data).
>
To my mind 1 second is a big time interval and keeping the two
applications separated will help you a lot in having a working system,
since you can concentrate on two different problems separately.
[...]
>
> I represent it as 2 independent problems. Thus an exchange of the
> program with the receiver it is desirable anything both not to interrupt
> in any way and not to stop at all.
I don't quite understand what you mean whit that.
>
> 08-10-2011 Terminal-log - example
> ---------------------------------
> sklimkin@sklimkin-desktop:~/projects/fdesign/surveyfd$ ./survey
> pixmap_file = /home/sklimkin/projects/fdesign/surveyfd/Garmin_iPAQ.xpm
> Function comport() in separated thread is running...
>
> PORTNAME=/dev/ttyS0
>
> USER PORTSPEED=9600
>
> WARNING! Press Ctrl+C to stop program!
> 16 bytes written to COM-port
> Binary file: /home/sklimkin/projects/fdesign/surveyfd/fileout.bin
> Bytes readed 537, found Garmin Message 0x33
>
> 2 Garmin commands is written!
> 605 bytes written in file
> 311 bytes written in file
> 311 bytes written in file
> ... ... ...
> 312 bytes written in file
> Segmentation fault
that is not a good sign, usually ;-)
> sklimkin@sklimkin-desktop:~/projects/fdesign/surveyfd$
>
> Depending on the receiver and from quantity of observable satellities,
> these lines can be from 300 to 2000 bytes of the binary data.
>
FWIK, depending on file system, usual access to file is in blocks of
4KB, so no difference in writing 300 or 2000.
> 605 bytes in the first line are 2 packages in the buffer serial-port.
> The program has begun dialogue with the receiver in the line:
> sleep (2); // in Sec
> BytesRead = read(fd, bRead, BUFSIZE);
> For a confident finding of the message on that what receiver is
> connected to port.
>
>> You can use fl_add_timeout() or fl_add_timer() to invoke the state
> machine if the comm. is very lengthy
> If it does not complicate you, some lines of a code on C-lang (can be
> with lines of comments) will be the most clear help.
I should mention that I found fdesign a very nice tool to check how your
interface will look like, but I will never use the source code produced
by fdesign, since the code I produce is much more maintainable and
readable than the one produced by the designer.
If you want to stick to fdesign I cannot advise how to add a timer or
timeout, but if you want I can point you to our libraries (which are not
very well documented though).
Thank you for these good examples. I rebuilt my program and report the results.
Unintelligible phrases in my posts you can just skip.
This is because I do not know English and use Internet software language-translator.
Sergey Klimkin.
I want to transfer a program created in xforms friends for testing.
If you run this program on another computer, you will receive an absence of the necessary libraries (quite naturally).
Terminal-log:
-------------
sklimkin@LinuxUbuntu:~$ cd /home/sklimkin/Projects
sklimkin@LinuxUbuntu:~/Projects$ ls
Garmin_iPAQ.xpm� survey
sklimkin@LinuxUbuntu:~/Projects$ ./survey
/survey: error while loading shared libraries: libforms.so.2: cannot open shared object file: No such file or directory
sklimkin@LinuxUbuntu:~/Projects$
That in this case can and should be applied to this program, so it was performed?
It is desirable to avoid installing xforms-1.0.xxxxxx
Sergey Klimkin.
On Tue, Oct 11, 2011 at 08:57:55AM -0700, Sergey Klimkin wrote:
> I want to transfer a program created in xforms friends for testing.
> If you run this program on another computer, you will receive an absence of
> the necessary libraries (quite naturally).
>
> Terminal-log:
> -------------
> sklimkin@LinuxUbuntu:~$ cd /home/sklimkin/Projects
> sklimkin@LinuxUbuntu:~/Projects$ ls
> Garmin_iPAQ.xpm� survey
> sklimkin@LinuxUbuntu:~/Projects$ ./survey
> ./survey: error while loading shared libraries: libforms.so.2: cannot open shared object file: No such file or directory
> sklimkin@LinuxUbuntu:~/Projects$
>
> That in this case can and should be applied to this program, so it was performed?
> It is desirable to avoid installing xforms-1.0.xxxxxx
In principle, you should be able to have both libraries installed
at once. But there can be problems: If for example, the old ver-
sion is installed in /usr/lib and the new one in /usr/local/lib
you rather likely will have in /usr/lib a symbolic link
/usr/lib/libforms.so pointing to /usr/lib/libforms.so.1.1.0
and in /usr/local/lib
/usr/local/lib/libforms.so pointing to /usr/local/lib/libforms.so.2.0.0
The linker will rather likely pick the wrong one, i.e. the
old version.
Problems with the compiler may also result when different
versions of the forms.h include file are installed (the
old version may have /usr/include/forms.h and the newer,
self0compiled version /usr/local/include/forms.h). Again,
the compiler may pick the old version of the header file
and thus problems could ensue.
So, if you have two versions of XForms installed make sure
that
a) there's only a single version of the header dile forms.h
exists (the one for the newer version, rather likely in
/usr/local/include)
b) make sure that the symbolic link /usr/lib/libforms.so
is deleted (other programs, still linked against the
old version of the library will continue to work, since
they are already linked they don't need that symbolic
link).
No, no! Probably the problem in my English.
On my computer, everything is in order. Installed only 1 copy of xforms, which works fine.
I booted from a flash card (Linux on SD-card), where there is no xforms and showed that informs the terminal if you run my program.
The same will be seen and my friends who want to test my program.
After all, they have no xforms.
So I asked: What are the minimum requirements to run programs written in xfotms when trying to run this program on the outsider computer?
Sergey.
On Tue, Oct 11, 2011 at 09:54:46AM -0700, Sergey Klimkin wrote:
> No, no! Probably the problem in my English. On my computer, everything is in
> order. Installed only 1 copy of xforms, which works fine.
> I booted from a flash card (Linux on SD-card), where there is no xforms and
>showed that informs the terminal if you run my program.
> The same will be seen and my friends who want to test my program. After all,
> they have no xforms.
Ok, now I understand.
> So I asked: What are the minimum requirements to run programs written in
> xfotms when trying to run this program on the outsider computer?
Well, you either install the library on the other computer or
you need to link statically (in which case the library becomes
part of the executable) and then you have to give your friend
the executable (which, of course, requires, that he's using a
computer that is similar emough, i.e. same processor type etc.).
If you want to link statically the simplest way I found on
my machine was to change the line
$(CC) survey_main.o survey.o survey_cb.o -o $(OUTPUT) -lforms -lpthread
in your Makefile to
$(CC) survey_main.o survey.o survey_cb.o -o $(OUTPUT) -lpthread -lm -lX11 -Xpm /usr/local/lib/libforms.a
That, of course, expects that on your friends machine everything
otherwise necessary is installed. If you want to see all libraries
your program is linked against use
ldd survey
which should give you a list of all those libraries.
just found some better way to do it:
$(CC) survey_main.o survey.o survey_cb.o -o $(OUTPUT) -Wl,-Bstatic -lforms -lXpm -Wl,-Bdynamic -lpthread -lm -lX11
This will link statically against the XForms and the Xpm li-
braries (which have a certain chance of not being available
on your friends computer) while linking dynamically against
the math, X11 and threads library (I would be astonished if
those would also be missing).
The '-Wl' option starts a command directly addressed to the
linker and '-Wl,-Bstatic' tells the linker to switch to static
and the following '-Wl,-Bdynamic' back to dynamic linking. As
a rule, statically linked libraries should come first.
Note that when linking dyamically against the XForms library
you don't have to link explicitely against the Xpm, math or
X11 libraries - they get included automatically. But that bit
of "magic" doesn't work anymore when linking statically, so
you have to link against them explicitely.
Sorry but's been years since I used static linking so my me-
mories of how it's done properly have become a bit hazy...