Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2015-04

Embedded Strings on nRF51-DK

40 messages · 10 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Paul Michell

Hello,

I'm using FPC to build embedded binaries for the Nordic Semiconductor nRF51-DK development board:

http://www.nordicsemi.com/eng/Products/nRF51-DK

I have been able to adapt the sample gcc make scripts to replace C units with equivalent pascal units after partially translating the header files from the SDK. This has enabled me to build test applications to use the board's buttons, LEDs, UART and timers.

However, when I try to use pascal string variables (short or long) the compiler fails. For example the following works:

Function Main: Integer; Cdecl; Alias: 'main';
Begin
  UARTConfigure(11, 9, 10, 8, True);
  UARTPutString('Hello World');
End;

But this fails:

Function Main: Integer; Cdecl; Alias: 'main';
Var
  Text: String;
Begin
  Text := 'Hello World';
  UARTConfigure(11, 9, 10, 8, True);
  UARTPutString(Text);
End;

With the following errors:

Main.pas:(.text.n_main_$$_main$$smallint+0xe): undefined reference to `fpc_pushexceptaddr'
Main.pas:(.text.n_main_$$_main$$smallint+0x12): undefined reference to `fpc_setjmp'
Main.pas:(.text.n_main_$$_main$$smallint+0x26): undefined reference to `fpc_shortstr_to_shortstr'
Main.pas:(.text.n_main_$$_main$$smallint+0x42): undefined reference to `fpc_shortstr_to_ansistr'
Main.pas:(.text.n_main_$$_main$$smallint+0x4e): undefined reference to `fpc_popaddrstack'
Main.pas:(.text.n_main_$$_main$$smallint+0x54): undefined reference to `fpc_ansistr_decr_ref'
Main.pas:(.text.n_main_$$_main$$smallint+0x64): undefined reference to `fpc_reraise'

I assume this is because string handling support is not included in the embedded RTL generated with the compiler, or that I am not linking the right object files if I need to do this by hand? What would be the best way to enable string handling? Even short string handling would make FPC far more preferable to C for me for embedded work.

Thanks,

Paul Michell

Reply by email

Sven Barth
to Paul Michell
"Paul Michell" wrote
I assume this is because string handling support is not included in the embedded RTL generated with the compiler, or that I am not linking the

right

object files if I need to do this by hand? What would be the best way to enable string handling? Even short string handling would make FPC far more preferable to C for me for embedded work.

First of: I don't know whether non-Shortstrings are supported on embedded (I haven't played with that target yet). So my following tips are geared towards ShortString usage.

Which compiler mode are you using? You should use either mode FPC or at most ObjFPC. Mode Delphi will switch on AnsiString. In any case you should ensure that you haven't enabled AnsiStrings using $H+ (simply disable the directive in that case).
Additionally you could declare your String variables explicitly as ShortString instead of String.

Regards,
Sven

Reply by email

Paul Michell
to Sven Barth
Sven Barth wrote 13 lines
First of: I don't know whether non-Shortstrings are supported on embedded (I haven't played with that target yet). So my following tips are geared towards ShortString usage. Which compiler mode are you using? You should use either mode FPC or at most ObjFPC. Mode Delphi will switch on AnsiString. In any case you should ensure that you haven't enabled AnsiStrings using $H+ (simply disable the directive in that case). Additionally you could declare your String variables explicitly as ShortString instead of String. Regards, Sven

I've tried mode FPC and ObjFPC with both long and short strings. I have just tried again with the ShortString type as well (I've included the whole main unit code below for reference).

I suspect that I need to link additional object files that support the string handling, but I don't know which ones, nor if this is possible with the embedded compiler?

Thanks,

Paul

--------------------------------------------
Unit Main;
{$Mode FPC}
{$LongStrings OFF}
Interface
Uses
  NRF51, UART;
Function Main: Integer; Cdecl;
Implementation
Function Main: Integer; Cdecl; Alias: 'main';
Const
  RXDPIN = 11;
  TXDPIN = 9;
  CTSPIN = 10;
  RTSPIN = 8;
Var
  Text: ShortString;
Begin
  Text := 'Hello World';
  UARTConfigure(RTSPIN, TXDPIN, CTSPIN, RXDPIN, True);
  UARTPutString(Text);
End;
End.

Reply by email

Sven Barth
to Paul Michell
"Paul Michell" wrote
On Thursday 16 Apr 2015 14:19:38 Sven Barth wrote: > First of: I don't know whether non-Shortstrings are supported on

embedded

Show quoted text 5 lines
> (I haven't played with that target yet). So my following tips are geared > towards ShortString usage. > > Which compiler mode are you using? You should use either mode FPC or at > most ObjFPC. Mode Delphi will switch on AnsiString. In any case you

should

> ensure that you haven't enabled AnsiStrings using $H+ (simply disable

the

Show quoted text 8 lines
> directive in that case). > Additionally you could declare your String variables explicitly as > ShortString instead of String. > > Regards, > Sven I've tried mode FPC and ObjFPC with both long and short strings. I have

just

tried again with the ShortString type as well (I've included the whole

main

unit code below for reference).

How about the unit UARTPutString is defined in? From the missing symbols you quoted earlier the compiler somewhere thinks that it needs to use an AnsiString and thus uses the corresponding functions which the linker the complains about.

I suspect that I need to link additional object files that support the

string

handling, but I don't know which ones, nor if this is possible with the embedded compiler?

As I wrote earlier I don't know enough about the embedded target right now to tell you whether it supports AnsiStrings at all and if so what you need to do to enable them.

Regards,
Sven

Reply by email

Paul Michell
to Sven Barth
Sven Barth wrote
How about the unit UARTPutString is defined in? From the missing symbols you quoted earlier the compiler somewhere thinks that it needs to use an AnsiString and thus uses the corresponding functions which the linker the complains about.

Yes that helped; LongStrings were ON in the UART module. When I changed that to OFF, the error report changed to:

Main.pas:(.text.n_main_$$_main$$longint+0xa): undefined reference to `fpc_shortstr_to_shortstr'

Which suggested to me I needed to link the object containing fpc_shortstr_to_shortstr explicitly as I am using the gcc make file. After a bit for searching I found the export in system.o which had been generated by the embedded compiler. Adding this to the make file resolved the the remaining error.

Sven, thank you for pointing me in the right direction!

Kind regards,

Paul

Reply by email

Sven Barth
to Paul Michell
Paul Michell wrote 17 lines
On Thursday 16 Apr 2015 17:18:21 Sven Barth wrote: > How about the unit UARTPutString is defined in? From the missing symbols > you quoted earlier the compiler somewhere thinks that it needs to use an > AnsiString and thus uses the corresponding functions which the linker the > complains about. Yes that helped; LongStrings were ON in the UART module. When I changed that to OFF, the error report changed to: Main.pas:(.text.n_main_$$_main$$longint+0xa): undefined reference to `fpc_shortstr_to_shortstr' Which suggested to me I needed to link the object containing fpc_shortstr_to_shortstr explicitly as I am using the gcc make file. After a bit for searching I found the export in system.o which had been generated by the embedded compiler. Adding this to the make file resolved the the remaining error.

Oh, so you're not letting FPC do the linking? If you'd have said that in your first mail then I could have told you as well that you need to have the system.o included.
Alternatively you could also use the option -sh which will generate a linker script for the host system and adjust that to your needs (though you'd need to do that every time you compile the units).

This also means that probably AnsiString will also work if you have the system.o (though maybe you'll also require a memory manager unit; AFAIK embedded needs an extra unit for that).

Regards,
sven

Reply by email

Jeppe Johansen
to Paul Michell: I'm using FPC to build embedded binaries for the Nordic Semiconductor nRF51-DK…
Paul Michell wrote 5 lines
I assume this is because string handling support is not included in the embedded RTL generated with the compiler, or that I am not linking the right object files if I need to do this by hand? What would be the best way to enable string handling? Even short string handling would make FPC far more preferable to C for me for embedded work.

You would make it a whole lot easier for yourself if you just used the Embedded target and added an actual controller type for that specific microcontroller. Then you wouldn't need to play around with linker scripts and manually including and trimming RTL files.

Adding the controller type is about 5-10 lines of code. Then the RTL unit can be a stub for now which basically just initializes .data and .bss.

If you have the name of the controller I can add it?

Reply by email

Georg Hieber
to Jeppe Johansen

Paul,
a few comments from somebody who is not a compiler developer, but who very recently started to get fpc running for another embedded platform, the avr.

1) you write somewhere that you ported things from c, and your examples start as
"function main: integer ..."
which looks to me exactly like int main().
In pascal, there is no need to declare a "function main". it is created automatically by the runtime system and contains the begin .. end block of your pascal program. In an embedded environment it is called immediately after some essential initialization (stack pointer, zeroing menory etc.), and if it returns, control goes to a system halt procedure.

2) if you build your crosscompiler with the command make clean all OS_TARGET=embedded CPU_TARGET=my_cpu make will not only build you a compiler but also a basic rtl (without, for example, file handling, as that needs an underlaying operating system), but which includes things like simple string handling. What this system includes and what not is controlled by the file <fpcbase>/rtl/embedded/rtl.cfg. For the beginning leave the default, minimal settings.

3) avoid ansistrings. They need heap management which is probably not available in the basic system, and consume much more resources than short strings.

4) how good (in the sense of efficient, short and fast execution code) or bad the rtl thus constructed is depends on how much work has already gone into porting fpc to the cpu / system combination you use. The rtl building process is using a clever sequence of conditional compiles to check if a certain function has already been implemented cpu and/or opsys specific, and if that is not the case, falls back to a generic procedure written in pascal that does the job, however not always in the most elegant way. The good part is, that from the beginning you will have a rtl that works.

5) unlike C, the fpc compiler depends on the existence of at least a minimal rtl (unit system), even if you don't call library functions explicitely. There are actually a lot of routines in system.pp and it's include files that are declared with the qualifier "compilerproc" which makes them invisible for the application program. Calls to these functions, however, appear, inserted directly by the compiler

6) there is no need to mess around with linker scripts etc. As long as you stay inside the "pascal world", i.e. write your application as a pascal program that can (or not) use several units, and do any necessary assembler programming using fpc's inline assembler, fpc will take care of the linking process. Either completely behind the scene, or, if you define so, by creating a linker script you can use. And even if you use external references (third party libraries, for example), if they are referenced by correctly declared pascal external functions, this should work.

7) the rtl unit system will be (smart-)linked automatically to your program, every other rtl unit has to be requested explicitely by a uses clause if their functionality is needed.

8) does your program have a "program", i.e. a main file that adheres to the syntax

program myprog
....declarations...
begin
....statements....
end.

I have only seen a "unit main", which for the fpc system is nothing more than one of probably many units, but which does not tell the compiler to link to the rtl (to be precise, to the unit system). The "program" does exactly that.

your examples look to me as if you are following your C habits, just writing in pascal. If that's correct - don't do it. Most likely, the problems you are encountering will dissapear as soon as you just let fpc and the basic rtl do their jobs. Do the following:

- build a compiler and rtl using OS_TARGET=embedded and CPU_TARGET whatever is closest to your actual cpu, which seems to be some arm variety.
- write your "main" as the begin .. end block of a program
- let fpc take care of the linking.

I hope what I wrote helps a little and does not bore too much,

Georg

Jeppe Johansen wrote 22 lines
On 04/16/2015 12:49 PM, Paul Michell wrote: > I assume this is because string handling support is not included in the > embedded RTL generated with the compiler, or that I am not linking > the right > object files if I need to do this by hand? What would be the best > way to > enable string handling? Even short string handling would make FPC far > more > preferable to C for me for embedded work. You would make it a whole lot easier for yourself if you just used the Embedded target and added an actual controller type for that specific microcontroller. Then you wouldn't need to play around with linker scripts and manually including and trimming RTL files. Adding the controller type is about 5-10 lines of code. Then the RTL unit can be a stub for now which basically just initializes .data and .bss. If you have the name of the controller I can add it? _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Michael Ring
to Jeppe Johansen: You would make it a whole lot easier for yourself if you just used the Embedded target…

Paul,

I can generate the pascal unit for the nrf51 module from the CMSIS Data of this chip.

Drop me a note if are you interested, this unit should make your life a lot easier.

Michael

Jeppe Johansen wrote 22 lines
On 04/16/2015 12:49 PM, Paul Michell wrote: > I assume this is because string handling support is not included in the > embedded RTL generated with the compiler, or that I am not linking > the right > object files if I need to do this by hand? What would be the best > way to > enable string handling? Even short string handling would make FPC far > more > preferable to C for me for embedded work. You would make it a whole lot easier for yourself if you just used the Embedded target and added an actual controller type for that specific microcontroller. Then you wouldn't need to play around with linker scripts and manually including and trimming RTL files. Adding the controller type is about 5-10 lines of code. Then the RTL unit can be a stub for now which basically just initializes .data and .bss. If you have the name of the controller I can add it? _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Paul Michell
to Sven Barth: Oh, so you're not letting FPC do the linking? If you'd have said that in your first mail…
Sven Barth wrote
Oh, so you're not letting FPC do the linking? If you'd have said that in your first mail then I could have told you as well that you need to have the system.o included.

Sorry for not being clear about that. This is my first step into the embedded world and I was trying to stay as close to the documented GCC process as possible until I understand enough to choose otherwise. I much prefer the FPC build mechanism to editing makefiles so I would prefer to use that if I can.

Alternatively you could also use the option -sh which will generate a linker script for the host system and adjust that to your needs (though you'd need to do that every time you compile the units).

I didn't know about -sh, that would be very useful in this context!

This also means that probably AnsiString will also work if you have the system.o (though maybe you'll also require a memory manager unit; AFAIK embedded needs an extra unit for that).

OK, I'll give that a try as well.

Thanks again,

Paul

Reply by email

Paul Michell
to Georg Hieber: a few comments from somebody who is not a compiler developer, but who very recently…

Georg

Thank you so much for the detailed response. Your points were very helpful. I've answered your questions in-line below:

Georg Hieber wrote
1) you write somewhere that you ported things from c, and your examples start as "function main: integer ..." which looks to me exactly like int main().

It is! I did a direct translation of the C example 'main.c'.

Show quoted text 8 lines
8) does your program have a "program", i.e. a main file that adheres to the syntax program myprog ....declarations... begin ....statements.... end.

Not at the moment. I would like to be able to do that, but I wasn't sure what would be involved in moving over to the full embedded compiler target. The Nordic Semiconductor platform has firmware to support its RF/Bluetooth hardware which has to be flashed independently and then I think the linker then targets a different address for the program depending upon configuration. Until I properly understand this process I did not want to step too far from the supported GCC mechanism.

I hope what I wrote helps a little and does not bore too much,

Not at all, thank you for sharing your insights.

Kind regards,

Paul

Reply by email

Paul Michell
to Michael Ring: I can generate the pascal unit for the nrf51 module from the CMSIS Data of this chip.…

Michael

Thanks for the offer of help. I'm totally new to embedded work. I am aware of the FPC embedded compiler target, but I don't yet understand the nRF51 SDK enough to set up the required files. I would like to move to this approach and I have read:

http://wiki.freepascal.org/TARGET_Embedded

What I am unsure about is how this would work with the RF/Bluetooth firmware of the nRF51. I have deliberately been staying as close to the GCC method as possible so that I can use all of the SDK resources. But if it is possible to use the target embedded approach that would be much better.

I don't know what the chip's CMSIS data is. I tried to google it and there is some mention of a 'SDK CMSIS pack' here:

http://developer.nordicsemi.com/

Does this tell you what needs to be known? Would you need to produce a different controller definition for each SoftDevice configuration?

If you think this is worth attempting I would be happy to help set this up.

Kind regards,

Paul

Michael Ring wrote 5 lines
I can generate the pascal unit for the nrf51 module from the CMSIS Data of this chip. Drop me a note if are you interested, this unit should make your life a lot easier.

Reply by email

Paul Michell
to Jeppe Johansen: You would make it a whole lot easier for yourself if you just used the Embedded target…

Jeppe

Thanks for the offer of help. Michael Ring also offered, perhaps we can coordinate our efforts.

Kind regards,

Paul

Jeppe Johansen wrote 19 lines
On 04/16/2015 12:49 PM, Paul Michell wrote: > I assume this is because string handling support is not included in the > embedded RTL generated with the compiler, or that I am not linking the > right object files if I need to do this by hand? What would be the best > way to enable string handling? Even short string handling would make FPC > far more preferable to C for me for embedded work. You would make it a whole lot easier for yourself if you just used the Embedded target and added an actual controller type for that specific microcontroller. Then you wouldn't need to play around with linker scripts and manually including and trimming RTL files. Adding the controller type is about 5-10 lines of code. Then the RTL unit can be a stub for now which basically just initializes .data and .bss. If you have the name of the controller I can add it? _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Michael Ring
to Paul Michell: Michael Thanks for the offer of help. I'm totally new to embedded work. I am aware of…

The CMSIS is a format created by ARM that (as one of it's features) describes all registers and fields of an arm chip in a language independant way.

I have created a patch for you that adds the interface-unit for the nrf51 chips.

Please check out a fresh copy of fpc-trunk

then apply this patch:

http://temp.michael-ring.org/nrf51.diff

and build the new compiler:

make clean buildbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm SUBARCH=armv6m CROSSOPT="-O2 -gw2" BINUTILSPREFIX=arm-none-eabi-

install it:

sudo make installbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm SUBARCH=armv6m CROSSOPT="-O2 -gw2" BINUTILSPREFIX=arm-none-eabi-

You may need o change BINUTILSPREFIX=arm-none-eabi- when your binutils have a different name and sudo is not necessary on windows

Now you have support for the nrf51 chips, ppcrossarm -i should give you:

nRF51822_xxAA,nRF51822_xxAB,nRF51822_xxAC,nRF51422_xxAA,nRF51422_xxAB nRF51422_xxAC

as new Microcontroller types.

This unit will help you with raw access to all registers, I am not sure if Nordic Semiconductor also offers documentation on this level, so your mileage may vary.

But you now have a basis to play arround with linking to the nrf51 libs and accessing the bluetooth stack provided by NC in the fpc way.

This is a helpfull way to do the compile:

ppcrossarm -MObjFPC -Scghi -al -Ch1024 -Cs1024 -Tembedded -Parm -vewnhix -l -Cparmv6m -O- -WpnRF51822_xxAC -XParm-none-eabi- -a hello.pas -sh

everything is compiled, but not linked.

you can then have a , check that all necessary sections are included. When happy you can call ppas.sh to do the actual linking.

I also have two nrf51 USB-thumb sticks please keep me posted on your success, I wanted to also do a small bluetooth project based on those modules. My plan was to do this in C (this is painful, but often the faster way) but I may switch to also try to do the project in fpc based on your results.....

Michael

Paul Michell wrote 37 lines
Michael Thanks for the offer of help. I'm totally new to embedded work. I am aware of the FPC embedded compiler target, but I don't yet understand the nRF51 SDK enough to set up the required files. I would like to move to this approach and I have read: http://wiki.freepascal.org/TARGET_Embedded What I am unsure about is how this would work with the RF/Bluetooth firmware of the nRF51. I have deliberately been staying as close to the GCC method as possible so that I can use all of the SDK resources. But if it is possible to use the target embedded approach that would be much better. I don't know what the chip's CMSIS data is. I tried to google it and there is some mention of a 'SDK CMSIS pack' here: http://developer.nordicsemi.com/ Does this tell you what needs to be known? Would you need to produce a different controller definition for each SoftDevice configuration? If you think this is worth attempting I would be happy to help set this up. Kind regards, Paul On Friday 17 Apr 2015 08:44:55 Michael Ring wrote: > I can generate the pascal unit for the nrf51 module from the CMSIS Data > of this chip. > > Drop me a note if are you interested, this unit should make your life a > lot easier. _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Paul Michell
to Michael Ring

Micheal

Michael Ring wrote
I have created a patch for you that adds the interface-unit for the nrf51 chips.

I've adapted my build script to generate the cross compiler from your patch. I've attached the actual script if you want to check that I've applied it correctly. It installs a ppcrossarm and RTL objects into /usr/lib/fpc/3.1.1/. When I run ppcrossarm -i I now get:

NRF51822_XXAA,NRF51822_XXAB,NRF51822_XXAC,NRF51422_XXAA,NRF51422_XXAB,NRF51422_XXAC,THUMB2_BARE

at the end of the supported microcontroller list. I have also found the new nrf51.pp unit which I assume is generated from the CMSIS data you mentioned?

Now I can use this to build a valid Cortex M0 executable without needing to use ld/make to perform the linking steps. I then use JLinkExe to perform the actual flashing of the nRF51. So my test build script is now:

ppcrossarm -MObjFPC -Scghi -al -Ch1024 -Cs1024 -Tembedded -Parm -vewnhix -l - Cparmv6m -O- -WpnRF51822_xxAC -XParm-none-eabi- -a test1.pas JLinkExe test1.jlink

Which is MUCH tidier than the GCC make script! Test1 is the preverbial simplest program:

Program test1;
Begin
  writeln('Hello World!');
End.

This (as expected) does nothing as writeln is not re-targeted to the UART.

My next test was to write a FPC 'blinky' clone using the TGPIO_Registers defined in your nrf51.pp unit (test2.pas attached). The main section of this looks like:

Procedure GPIOTogglePin(PinNumber: LongWord); Inline;
Var
  PinBit: LongWord;
Begin
  PinBit := LongWord(1) ShL PinNumber;
  If (GPIO.OUT And PinBit)=0 Then
    GPIO.OUTSET := PinBit
  Else
    GPIO.OUTCLR := PinBit;
End;
Const
  LED1 = 21;
Begin
  GPIO.PIN_CNF21_bits.SENSE := 0;
  GPIO.PIN_CNF21_bits.DRIVE := 0;
  GPIO.PIN_CNF21_bits.PULL := 0;
  GPIO.PIN_CNF21_bits.clearINPUT;
  GPIO.PIN_CNF21_bits.setDIR;
  While True Do
    Begin
      GPIOTogglePin(LED1);
      MillisecondsDelay(1000);
    End;
End.

I think this is still easier to read than the equivalent C, although it would be nicer still to be able to use the pin number as an array index, something like this:

GPIO.PinConfig[LED1].setDIR;
GPIO.Pin[LED1].Clear;

At this point I decided to split the code into 2 modules so that utilities such as GPIOTogglePin and MillisecondsDelay were not defined in the main unit. This gives test3.pas and nRF51Utils.pas. As expected, FPC implicitly built and linked nRF51Utils. This is a great improvement over having to edit a makefile every time I want to introduce a new unit!

Next I wanted to enable UART output so that I could do basic debugging.

Unfortunately the fun starts when I try to elaborate this!

In nrf51.h I notice the pin config array is defined as:

PIN_CNF[32];

But the TGPIO_Registers in nrf51.pp defines PIN_CNF0 to PIN_CNF32. Should that be to PIN_CNF31?

Show quoted text 16 lines
The CMSIS is a format created by ARM that (as one of it's features) describes all registers and fields of an arm chip in a language independant way. Please check out a fresh copy of fpc-trunk then apply this patch: http://temp.michael-ring.org/nrf51.diff and build the new compiler: make clean buildbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm SUBARCH=armv6m CROSSOPT="-O2 -gw2" BINUTILSPREFIX=arm-none-eabi-

make buildbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm SUBARCH=armv6m CROSSOPT="-O2 -gw2" CROSSBINDIR=/usr/bin/ BINUTILSPREFIX=arm-none-eabi-

Show quoted text 5 lines
install it: sudo make installbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm SUBARCH=armv6m CROSSOPT="-O2 -gw2" BINUTILSPREFIX=arm-none-eabi-

sudo make installbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm SUBARCH=armv6m CROSSOPT="-O2 -gw2" BINUTILSPREFIX=arm-none-eabi- PREFIX=/usr

Show quoted text 82 lines
You may need o change BINUTILSPREFIX=arm-none-eabi- when your binutils have a different name and sudo is not necessary on windows Now you have support for the nrf51 chips, ppcrossarm -i should give you: nRF51822_xxAA,nRF51822_xxAB,nRF51822_xxAC,nRF51422_xxAA,nRF51422_xxAB nRF51422_xxAC as new Microcontroller types. This unit will help you with raw access to all registers, I am not sure if Nordic Semiconductor also offers documentation on this level, so your mileage may vary. But you now have a basis to play arround with linking to the nrf51 libs and accessing the bluetooth stack provided by NC in the fpc way. This is a helpfull way to do the compile: ppcrossarm -MObjFPC -Scghi -al -Ch1024 -Cs1024 -Tembedded -Parm -vewnhix -l -Cparmv6m -O- -WpnRF51822_xxAC -XParm-none-eabi- -a hello.pas -sh everything is compiled, but not linked. you can then have a , check that all necessary sections are included. When happy you can call ppas.sh to do the actual linking. I also have two nrf51 USB-thumb sticks please keep me posted on your success, I wanted to also do a small bluetooth project based on those modules. My plan was to do this in C (this is painful, but often the faster way) but I may switch to also try to do the project in fpc based on your results..... Michael Am 18.04.15 um 11:16 schrieb Paul Michell: > Michael > > Thanks for the offer of help. I'm totally new to embedded work. I am > aware of the FPC embedded compiler target, but I don't yet understand > the nRF51 SDK enough to set up the required files. I would like to move > to this approach and I have read: > > http://wiki.freepascal.org/TARGET_Embedded > > What I am unsure about is how this would work with the RF/Bluetooth > firmware of the nRF51. I have deliberately been staying as close to the > GCC method as possible so that I can use all of the SDK resources. But > if it is possible to use the target embedded approach that would be much > better. > > I don't know what the chip's CMSIS data is. I tried to google it and > there is some mention of a 'SDK CMSIS pack' here: > > http://developer.nordicsemi.com/ > > Does this tell you what needs to be known? Would you need to produce a > different controller definition for each SoftDevice configuration? > > If you think this is worth attempting I would be happy to help set this > up. > > Kind regards, > > Paul > > On Friday 17 Apr 2015 08:44:55 Michael Ring wrote: >> I can generate the pascal unit for the nrf51 module from the CMSIS Data >> of this chip. >> >> Drop me a note if are you interested, this unit should make your life a >> lot easier. > > _______________________________________________ > fpc-devel maillist - > http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Michael Ring
to Paul Michell: Micheal I've adapted my build script to generate the cross compiler from your patch. I've…

Hey! it looks like you are making good progress!

I know, in the current state the generated headers still require you to write a lot of code as they are really only a thin wrapper arround the registers and bits.

For pic32 I have already created some extra wrapper scripts, blinky looks there like this, and it is more super-blinky as it flashes 10 LED's at a time ;-) ;-)
I am in the process of testing a way to also generate those more user friendly additional wrappers.

I will check if there's an error in the generator, PIN_CNF32 looks really really wrong...

program hello;
uses
   pic32mx_gpio_ansel;
var
   i : longword; //Thank you Jeppe ;-)
begin
GPIOA.setConfig([RA0,RA1,RA2,RA3,RA4,RA7,RA8,RA9,RA10],GPIO_Output_Push_Pull);
while true do
begin
   GPIOA.clearBit([RA0,RA1,RA2,RA3,RA4,RA7,RA8,RA9,RA10]);
   for i := 0 to 40000 do
     ;
   GPIOA.setBit([RA0,RA1,RA2,RA3,RA4,RA7,RA8,RA9,RA10]);
   for i := 0 to 40000 do
     ;
end;
end.
Paul Michell wrote 200 lines
Micheal On Sunday 19 Apr 2015 17:24:35 Michael Ring wrote: > I have created a patch for you that adds the interface-unit for the > nrf51 chips. I've adapted my build script to generate the cross compiler from your patch. I've attached the actual script if you want to check that I've applied it correctly. It installs a ppcrossarm and RTL objects into /usr/lib/fpc/3.1.1/. When I run ppcrossarm -i I now get: NRF51822_XXAA,NRF51822_XXAB,NRF51822_XXAC,NRF51422_XXAA,NRF51422_XXAB,NRF51422_XXAC,THUMB2_BARE at the end of the supported microcontroller list. I have also found the new nrf51.pp unit which I assume is generated from the CMSIS data you mentioned? Now I can use this to build a valid Cortex M0 executable without needing to use ld/make to perform the linking steps. I then use JLinkExe to perform the actual flashing of the nRF51. So my test build script is now: ppcrossarm -MObjFPC -Scghi -al -Ch1024 -Cs1024 -Tembedded -Parm -vewnhix -l - Cparmv6m -O- -WpnRF51822_xxAC -XParm-none-eabi- -a test1.pas JLinkExe test1.jlink Which is MUCH tidier than the GCC make script! Test1 is the preverbial simplest program: Program test1; Begin writeln('Hello World!'); End. This (as expected) does nothing as writeln is not re-targeted to the UART. My next test was to write a FPC 'blinky' clone using the TGPIO_Registers defined in your nrf51.pp unit (test2.pas attached). The main section of this looks like: Procedure GPIOTogglePin(PinNumber: LongWord); Inline; Var PinBit: LongWord; Begin PinBit := LongWord(1) ShL PinNumber; If (GPIO.OUT And PinBit)=0 Then GPIO.OUTSET := PinBit Else GPIO.OUTCLR := PinBit; End; Const LED1 = 21; Begin GPIO.PIN_CNF21_bits.SENSE := 0; GPIO.PIN_CNF21_bits.DRIVE := 0; GPIO.PIN_CNF21_bits.PULL := 0; GPIO.PIN_CNF21_bits.clearINPUT; GPIO.PIN_CNF21_bits.setDIR; While True Do Begin GPIOTogglePin(LED1); MillisecondsDelay(1000); End; End. I think this is still easier to read than the equivalent C, although it would be nicer still to be able to use the pin number as an array index, something like this: GPIO.PinConfig[LED1].setDIR; GPIO.Pin[LED1].Clear; At this point I decided to split the code into 2 modules so that utilities such as GPIOTogglePin and MillisecondsDelay were not defined in the main unit. This gives test3.pas and nRF51Utils.pas. As expected, FPC implicitly built and linked nRF51Utils. This is a great improvement over having to edit a makefile every time I want to introduce a new unit! Next I wanted to enable UART output so that I could do basic debugging. Unfortunately the fun starts when I try to elaborate this! In nrf51.h I notice the pin config array is defined as: PIN_CNF[32]; But the TGPIO_Registers in nrf51.pp defines PIN_CNF0 to PIN_CNF32. Should that be to PIN_CNF31? > The CMSIS is a format created by ARM that (as one of it's features) > describes all registers and fields of an arm chip in a language > independant way. > > > > Please check out a fresh copy of fpc-trunk > > then apply this patch: > > http://temp.michael-ring.org/nrf51.diff > > and build the new compiler: > > make clean buildbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm > SUBARCH=armv6m CROSSOPT="-O2 -gw2" BINUTILSPREFIX=arm-none-eabi- make buildbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm SUBARCH=armv6m CROSSOPT="-O2 -gw2" CROSSBINDIR=/usr/bin/ BINUTILSPREFIX=arm-none-eabi- > install it: > > sudo make installbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm > SUBARCH=armv6m CROSSOPT="-O2 -gw2" BINUTILSPREFIX=arm-none-eabi- sudo make installbase CROSSINSTALL=1 OS_TARGET=embedded CPU_TARGET=arm SUBARCH=armv6m CROSSOPT="-O2 -gw2" BINUTILSPREFIX=arm-none-eabi- PREFIX=/usr > You may need o change BINUTILSPREFIX=arm-none-eabi- when your binutils > have a different name and sudo is not necessary on windows > > Now you have support for the nrf51 chips, ppcrossarm -i should give you: > > nRF51822_xxAA,nRF51822_xxAB,nRF51822_xxAC,nRF51422_xxAA,nRF51422_xxAB > nRF51422_xxAC > > as new Microcontroller types. > > This unit will help you with raw access to all registers, I am not sure > if Nordic Semiconductor also offers documentation on this level, so your > mileage may vary. > > But you now have a basis to play arround with linking to the nrf51 libs > and accessing the bluetooth stack provided by NC in the fpc way. > > This is a helpfull way to do the compile: > > ppcrossarm -MObjFPC -Scghi -al -Ch1024 -Cs1024 -Tembedded -Parm -vewnhix > -l -Cparmv6m -O- -WpnRF51822_xxAC -XParm-none-eabi- -a hello.pas -sh > > everything is compiled, but not linked. > > you can then have a , check that all necessary sections > are included. When happy you can call ppas.sh to do the actual linking. > > I also have two nrf51 USB-thumb sticks please keep me posted on your > success, I wanted to also do a small bluetooth project based on those > modules. My plan was to do this in C (this is painful, but often the > faster way) but I may switch to also try to do the project in fpc based > on your results..... > > > Michael > > Am 18.04.15 um 11:16 schrieb Paul Michell: >> Michael >> >> Thanks for the offer of help. I'm totally new to embedded work. I am >> aware of the FPC embedded compiler target, but I don't yet understand >> the nRF51 SDK enough to set up the required files. I would like to move >> to this approach and I have read: >> >> http://wiki.freepascal.org/TARGET_Embedded >> >> What I am unsure about is how this would work with the RF/Bluetooth >> firmware of the nRF51. I have deliberately been staying as close to the >> GCC method as possible so that I can use all of the SDK resources. But >> if it is possible to use the target embedded approach that would be much >> better. >> >> I don't know what the chip's CMSIS data is. I tried to google it and >> there is some mention of a 'SDK CMSIS pack' here: >> >> http://developer.nordicsemi.com/ >> >> Does this tell you what needs to be known? Would you need to produce a >> different controller definition for each SoftDevice configuration? >> >> If you think this is worth attempting I would be happy to help set this >> up. >> >> Kind regards, >> >> Paul >> >> On Friday 17 Apr 2015 08:44:55 Michael Ring wrote: >>> I can generate the pascal unit for the nrf51 module from the CMSIS Data >>> of this chip. >>> >>> Drop me a note if are you interested, this unit should make your life a >>> lot easier. >> _______________________________________________ >> fpc-devel maillist - >> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel > _______________________________________________ > fpc-devel maillist - > http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel > > > _______________________________________________ > fpc-devel maillist - > http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Paul Michell
to Paul Michell: Apologies, my last email is a draft that I pressed send on by mistake! I'll re-send it…

Micheal,

I have started to encounter problems with the UART handling. Test4 starts to add some program logic and construct debugging messages back through the UART functions.

The first problem is a corrupting of the system start message, although subsequent message output is fine? This can be seen in the attached image. Strangely, I have found by trial and error, that removing:

      GPIOOutputPin(TXDPinNumber);

from the UARTConfigure procedure (which is a line-for-line translation of the original GCC function) makes this issue go away! I don't understand why this happens, nor if it is safe for me to leave out this line permanently from the procedure?

Secondly, the run counter should be formatted by the string expression:

      MessageText := 'Run: '+IntToStr(RunCount)+#13#10;
      UARTSendString(MessageText);

All that is actually printed is the RunCount number. This can also be seen in the screen shot. I wonder if there is some aspect of the string handling that is still not being linked? If so, would it be possible to fix this, as this sort of trivial text construction is a major benefit of Pascal over C.

I have also managed to get button input working and some initial success with using timer interrupts rather than the rather clumsy wait loops included in these tests. At the moment this code still uses my old nRF51 header translation. I will next work on converting these to use your header layout. I would be happy to post these here if anyone would like them?

After this I want to start looking at how to use the RF/Bluetooth softdevice, has anyone else tried this yet?

Thanks,

Paul

Reply by email

Michael Ring
to Paul Michell

One question, why do you enable flow control? Afaik the serial interface only uses rx/tx.

For the strings problem, I guess it's time to start up the debugger ;-) (I am removing the dust from my nrf51 dongle, too ;-) )

It looks like you are on Linux, can you please install cgdb and make sure that you also have arm-none-eabi-gdb ?

Start

JLinkGDBServer -if swd

Then for very low level debugging you can do:

BIN=hello.elf
arm-none-eabi-gdb $BIN --tui --eval-command="target extended :2331" --eval-command="monitor reset" --eval-command="monitor halt" --eval-command="set mem inaccessible-by-default off" --eval-command="load" --eval-command="layout asm" --eval-command="layout regs"

For source code debugging the nicer solution is to use cgdb:

BIN=hello.elf
cgdb -d arm-none-eabi-gdb $BIN -- --eval-command="target extended :2331" --eval-command="monitor reset" --eval-command="monitor halt" --eval-command="set mem inaccessible-by-default off" --eval-command="load"

When cgdb is up you can first do:

break main
cont
cont

then hit 'ESC', you are now in the top window, with F8 / F10 You can step over/into your code,
hit i, then you are back in the lower window and can inspect variables.

Michael

Paul Michell wrote 45 lines
Micheal, I have started to encounter problems with the UART handling. Test4 starts to add some program logic and construct debugging messages back through the UART functions. The first problem is a corrupting of the system start message, although subsequent message output is fine? This can be seen in the attached image. Strangely, I have found by trial and error, that removing: GPIOOutputPin(TXDPinNumber); from the UARTConfigure procedure (which is a line-for-line translation of the original GCC function) makes this issue go away! I don't understand why this happens, nor if it is safe for me to leave out this line permanently from the procedure? Secondly, the run counter should be formatted by the string expression: MessageText := 'Run: '+IntToStr(RunCount)+#13#10; UARTSendString(MessageText); All that is actually printed is the RunCount number. This can also be seen in the screen shot. I wonder if there is some aspect of the string handling that is still not being linked? If so, would it be possible to fix this, as this sort of trivial text construction is a major benefit of Pascal over C. I have also managed to get button input working and some initial success with using timer interrupts rather than the rather clumsy wait loops included in these tests. At the moment this code still uses my old nRF51 header translation. I will next work on converting these to use your header layout. I would be happy to post these here if anyone would like them? After this I want to start looking at how to use the RF/Bluetooth softdevice, has anyone else tried this yet? Thanks, Paul _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Paul Michell
to Michael Ring
Michael Ring wrote
One question, why do you enable flow control? Afaik the serial interface only uses rx/tx.

Due to ignorance! I'm completely new to this type of work, so I am very much learning the subtleties of bare metal programming. Any settings choices are simply reflections of the original C samples I am working from. I'll see if switching off flow control sorts out the corruption issue.

It looks like you are on Linux, can you please install cgdb and make sure that you also have arm-none-eabi-gdb ?

Ok, I'll give gdb a try this afternoon.

Thanks,

Paul

Reply by email

Alfred
to Paul Michell

Hello to all.

While working on fpcup, I did encounter the following problem.

Fpcup has modules that implement automatic download and install of packages.
One of these modules is indy.

Indy has a svn server that needs a username. No password is needed. However, if a username is given to a command line svn client, this svn-client wants to have a password too.
This password has to be empty.

Fpcup uses TProcess to execute commands.
But it seems that TProcess cannot handle empty parameters correctly (on Linux).

It processes the parameters, including the empty password, by generating a list of (p)pchar strings.
It uses strnew to accomplish this.
But strnew returns nil for an empty string (Delphi does not return nil in this case).

My question:

Is this expected behavior of TProcess ?
Or should TProcess be changed.
Or strnew (and strpas) ?

Thanks.

Additional info
Sourcefile : process.inc, inside fpc\packages\fcl-process\src\unix :
Function StringsToPCharList(List : TStrings) : PPChar;
Var
   I : Integer;
   S : String;
begin
   I:=(List.Count)+1;
   GetMem(Result,I*sizeOf(PChar));
   PPCharArray(Result)^[List.Count]:=Nil;
   For I:=0 to List.Count-1 do
   begin
     S:=List[i];
     Result[i]:=StrNew(PChar(S)); <--------------------------- here
   end;
end;

Reply by email

Michael Van Canneyt
to Alfred
Alfred wrote 15 lines
Hello to all. While working on fpcup, I did encounter the following problem. Fpcup has modules that implement automatic download and install of packages. One of these modules is indy. Indy has a svn server that needs a username. No password is needed. However, if a username is given to a command line svn client, this svn-client wants to have a password too. This password has to be empty. Fpcup uses TProcess to execute commands. But it seems that TProcess cannot handle empty parameters correctly (on Linux).

That is debatable:

The question is: how does a C program interpret a Nil argv[] pointer ? Because a Nil pointer is added to the Argv[] array, so the argument is there.

Show quoted text 5 lines
It processes the parameters, including the empty password, by generating a list of (p)pchar strings. It uses strnew to accomplish this. But strnew returns nil for an empty string (Delphi does not return nil in this case).

Do you have a test for this ?

Show quoted text 23 lines
My question: Is this expected behavior of TProcess ? Or should TProcess be changed. Or strnew (and strpas) ? Thanks. Additional info Sourcefile : process.inc, inside fpc\packages\fcl-process\src\unix : Function StringsToPCharList(List : TStrings) : PPChar; Var I : Integer; S : String; begin I:=(List.Count)+1; GetMem(Result,I*sizeOf(PChar)); PPCharArray(Result)^[List.Count]:=Nil; For I:=0 to List.Count-1 do begin S:=List[i]; Result[i]:=StrNew(PChar(S)); <--------------------------- here

Pchar(S) will return a pointer to an empty string (essentially, a pointer to a #0 char) if S is empty. That means that StrNew would need to be adapted.

However, for backwards compatibility with FPC, it may be better to simply change TProcess to add a pointer to a zero character #0

Michael.

Reply by email

Alfred
to Michael Van Canneyt

Thanks for your answer !

To be honest, I do not know exactly what to do to solve this problem.

If I look at the source of TProcess, a lot of thing are done with the parameters.
The parameters are parsed into a list. And again converted into a PCharList.
And some info is lost during these conversions.

The (unix) command involved is:
Exe='svn';
Cmd:='checkout --username "ausername" --password "" -r HEAD remoterepo
localrepo';
ExecuteCommand(Exe+' '+Cmd,....);

As the command itself is a single string, I do not understand why all parameters are split and then combined again. In all conversions, the empty password string is lost when using ExecuteCommand from the processutils unit.

In my search, I came across StrPas and StrNew, and found out that they return nil for empty string, as opposed to Delphi. But again, I do not know if this has something to do with this empty string problem.

As a workaround fpcup now uses: fpSystem(Exe+' '+Command); But I have to use some trickery to get the output from this command. I would prefer to use ExecuteCommand on all architectures.

Reply by email

Michael Van Canneyt
to Alfred
Alfred wrote 8 lines
Thanks for your answer ! To be honest, I do not know exactly what to do to solve this problem. If I look at the source of TProcess, a lot of thing are done with the parameters. The parameters are parsed into a list. And again converted into a PCharList. And some info is lost during these conversions.

That is only if you use the CommandLine property.
If you use the stringlist (Parameters), no parsing is done. Each parameter must be a separate item in the list.

Show quoted text 10 lines
The (unix) command involved is: Exe='svn'; Cmd:='checkout --username "ausername" --password "" -r HEAD remoterepo localrepo'; ExecuteCommand(Exe+' '+Cmd,....); As the command itself is a single string, I do not understand why all parameters are split and then combined again. In all conversions, the empty password string is lost when using ExecuteCommand from the processutils unit.

I don't know what code you are looking at but the unix version of TProcess uses ExecVE.

Show quoted text 8 lines
In my search, I came across StrPas and StrNew, and found out that they return nil for empty string, as opposed to Delphi. But again, I do not know if this has something to do with this empty string problem. As a workaround fpcup now uses: fpSystem(Exe+' '+Command); But I have to use some trickery to get the output from this command. I would prefer to use ExecuteCommand on all architectures.

Where did you find this ExecuteCommand ? It's definitely not in FPC.

Michael.

Reply by email

Marco van de Voort
to Michael Van Canneyt

In our previous episode, Michael Van Canneyt said:

Show quoted text 9 lines
> Cmd:='checkout --username "ausername" --password "" -r HEAD remoterepo > localrepo'; > ExecuteCommand(Exe+' '+Cmd,....); > > As the command itself is a single string, I do not understand why all > parameters are split and then combined again. In all conversions, the empty > password string is lost when using ExecuteCommand from the processutils unit. I don't know what code you are looking at but the unix version of TProcess uses ExecVE.

(processutils is an unit from Ludo used and extended by Reinier for fpcup, which he later extended with Runcommand variants because he still wanted to support 2.6.0.

Some of the prototypes (though not the current code) was what spawned the runcommand functions.

So basically they are helpers that are tied to fpcup because of its one single commandline internal limitations (still?) and 2.6.0 legacy support.

Both are reasons to not use the unit in new codebases (though maybe we should adapt some of the environment support)

https://bitbucket.org/reiniero/fpcup/src/b2d024f1a6d2c378585c8114866f6fa3a82fa3f3/processutils.pas?at=default )

Reply by email

Marco van de Voort
to Michael Van Canneyt: That is only if you use the CommandLine property. If you use the stringlist (Parameters),…

In our previous episode, Michael Van Canneyt said:

(on rereading the whole thread)

That is only if you use the CommandLine property. If you use the stringlist (Parameters), no parsing is done.

The mentioned routine is the tstringlist to array of pchar conversion, and afaik also applies to the separated part.

Since NIL is a termination of an array of pchar in C that is not ok.

behaviour of strnew should be checked in both TP and Delphi (since both have strnew) and if necessary changed. (returning FPC_EMPTYCHAR or whatever)

If it can't be changed, it must be worked around in process.inc.

That being said, it is a very good idea for fpcup maintainers to cleanup legacy as much as possible, and work towards representing a commandline as an array of string, and not a single string.

Reply by email

Michael Van Canneyt
to Marco van de Voort
Marco van de Voort wrote 11 lines
In our previous episode, Michael Van Canneyt said: (on rereading the whole thread) > That is only if you use the CommandLine property. > If you use the stringlist (Parameters), no parsing is done. The mentioned routine is the tstringlist to array of pchar conversion, and afaik also applies to the separated part. Since NIL is a termination of an array of pchar in C that is not ok.

if that were the case, argc would not have been introduced, which is why I doubt the use of this argument ?

C code that regards nil as the last element of the argv array is just wrong.

In each case, it is not relevant to the discussion.

Show quoted text 5 lines
behaviour of strnew should be checked in both TP and Delphi (since both have strnew) and if necessary changed. (returning FPC_EMPTYCHAR or whatever) If it can't be changed, it must be worked around in process.inc.

Exactly my initial point.

Show quoted text 5 lines
That being said, it is a very good idea for fpcup maintainers to cleanup legacy as much as possible, and work towards representing a commandline as an array of string, and not a single string.

Indeed, agreed 100%.

If the code still used commandline, then that must be changed to the new parameters. If I recall correctly, commandline is marked deprecated so it should be easy to spot.

Michael.

Reply by email

Henry Vermaak
to Michael Van Canneyt
Michael Van Canneyt wrote 20 lines
On Thu, 7 May 2015, Marco van de Voort wrote: >In our previous episode, Michael Van Canneyt said: > >(on rereading the whole thread) > >>That is only if you use the CommandLine property. >>If you use the stringlist (Parameters), no parsing is done. > >The mentioned routine is the tstringlist to array of pchar conversion, and >afaik also applies to the separated part. > >Since NIL is a termination of an array of pchar in C that is not ok. if that were the case, argc would not have been introduced, which is why I doubt the use of this argument ? C code that regards nil as the last element of the argv array is just wrong.

The C standard says that argv[argc] shall be a null pointer.

Henry

Reply by email

Michael Van Canneyt
to Henry Vermaak
Henry Vermaak wrote 23 lines
On Thu, May 07, 2015 at 12:59:52PM +0200, Michael Van Canneyt wrote: > > > On Thu, 7 May 2015, Marco van de Voort wrote: > >> In our previous episode, Michael Van Canneyt said: >> >> (on rereading the whole thread) >> >>> That is only if you use the CommandLine property. >>> If you use the stringlist (Parameters), no parsing is done. >> >> The mentioned routine is the tstringlist to array of pchar conversion, and >> afaik also applies to the separated part. >> >> Since NIL is a termination of an array of pchar in C that is not ok. > > if that were the case, argc would not have been introduced, which is > why I doubt the use of this argument ? > > C code that regards nil as the last element of the argv array is just wrong. The C standard says that argv[argc] shall be a null pointer.

So if argc is 15, there should be no problem to have a Nil at position 5 ?

Michael.

Reply by email

Henry Vermaak
to Michael Van Canneyt
Michael Van Canneyt wrote 10 lines
On Thu, 7 May 2015, Henry Vermaak wrote: >On Thu, May 07, 2015 at 12:59:52PM +0200, Michael Van Canneyt wrote: >>if that were the case, argc would not have been introduced, which is >>why I doubt the use of this argument ? >> >>C code that regards nil as the last element of the argv array is just wrong. > >The C standard says that argv[argc] shall be a null pointer. So if argc is 15, there should be no problem to have a Nil at position 5 ?

The standard also says that argv[0] to argv[argc-1] shall contain pointers to strings. NULL is not a pointer to a string, so that would be a problem.

Henry

Reply by email

Marco van de Voort
to Michael Van Canneyt: if that were the case, argc would not have been introduced, which is why I doubt the use…

In our previous episode, Michael Van Canneyt said:

Show quoted text 5 lines
> > Since NIL is a termination of an array of pchar in C that is not ok. if that were the case, argc would not have been introduced, which is why I doubt the use of this argument ?

Where is argc on the calling side? In the parameters of ExecVE ? Right.

C code that regards nil as the last element of the argv array is just wrong.

IMHO *nix is not terribly well designed. Probably the multitude of versions and being interwoven with C prohibited doing massive cleanups.

> behaviour of strnew should be checked in both TP and Delphi (since both have > strnew) and if necessary changed. (returning FPC_EMPTYCHAR or whatever)

As for Delphi,

uses
  System.SysUtils;
var p : pchar;
begin
  p:=strnew('');
  writeln(assigned(p),' ',ord(p^));
  readln;
end.

writes "TRUE 0"

so it seems to be the emptychar story. Better fix that as well. Unfortunately, FPC_emptychar is not exported from system.

Reply by email

Henry Vermaak
to Marco van de Voort
Marco van de Voort wrote 14 lines
In our previous episode, Michael Van Canneyt said: > > > > Since NIL is a termination of an array of pchar in C that is not ok. > > if that were the case, argc would not have been introduced, > which is why I doubt the use of this argument ? Where is argc on the calling side? In the parameters of ExecVE ? Right. > C code that regards nil as the last element of the argv array is just > wrong. IMHO *nix is not terribly well designed. Probably the multitude of versions and being interwoven with C prohibited doing massive cleanups.

The (redundant) argv[argc] == NULL thing was added because of common practice, I think. It's pretty common to see while (*argv) {...}.

Henry

Reply by email

Michael Van Canneyt
to Henry Vermaak: The standard also says that argv[0] to argv[argc-1] shall contain pointers to strings. …
Henry Vermaak wrote 15 lines
On Thu, May 07, 2015 at 01:55:37PM +0200, Michael Van Canneyt wrote: > On Thu, 7 May 2015, Henry Vermaak wrote: >> On Thu, May 07, 2015 at 12:59:52PM +0200, Michael Van Canneyt wrote: >>> if that were the case, argc would not have been introduced, which is >>> why I doubt the use of this argument ? >>> >>> C code that regards nil as the last element of the argv array is just wrong. >> >> The C standard says that argv[argc] shall be a null pointer. > > So if argc is 15, there should be no problem to have a Nil at position 5 ? The standard also says that argv[0] to argv[argc-1] shall contain pointers to strings. NULL is not a pointer to a string, so that would be a problem.

Indeed.
So, in any case, we'll need to adapt TProcess.

Michael.

Reply by email

Michael Van Canneyt
to Marco van de Voort: In our previous episode, Michael Van Canneyt said: Where is argc on the calling side? In…
Marco van de Voort wrote 14 lines
In our previous episode, Michael Van Canneyt said: >> >> Since NIL is a termination of an array of pchar in C that is not ok. > > if that were the case, argc would not have been introduced, > which is why I doubt the use of this argument ? Where is argc on the calling side? In the parameters of ExecVE ? Right. > C code that regards nil as the last element of the argv array is just > wrong. IMHO *nix is not terribly well designed. Probably the multitude of versions and being interwoven with C prohibited doing massive cleanups.

This argument can be applied to any OS older than 5 years :)

Backwards compatibility probably prevents any OS from being considered 'well designed'.

Show quoted text 19 lines
>> behaviour of strnew should be checked in both TP and Delphi (since both have >> strnew) and if necessary changed. (returning FPC_EMPTYCHAR or whatever) As for Delphi, uses System.SysUtils; var p : pchar; begin p:=strnew(''); writeln(assigned(p),' ',ord(p^)); readln; end. writes "TRUE 0" so it seems to be the emptychar story. Better fix that as well. Unfortunately, FPC_emptychar is not exported from system.

No, and you cannot use that directly, because in case of an error, the items in the argv array and the array itself are freed (or so I hope). The FPC_emptychar pointer should not be freed...

fixing strnew() to allocate a single #0 on the heap is probably best.

Michael.

Reply by email

Marco van de Voort
to Michael Van Canneyt: Indeed. So, in any case, we'll need to adapt TProcess. Michael.

In our previous episode, Michael Van Canneyt said:

Show quoted text 10 lines
>>> The C standard says that argv[argc] shall be a null pointer. >> >> So if argc is 15, there should be no problem to have a Nil at position 5 ? > > The standard also says that argv[0] to argv[argc-1] shall contain > pointers to strings. NULL is not a pointer to a string, so that would > be a problem. Indeed. So, in any case, we'll need to adapt TProcess.

No, strnew, since it is not delphi compatible and should simply always allocate a string.

Index: syspch.inc
=================================================================== --- syspch.inc (revision 30815)
+++ syspch.inc (working copy)
@@ -28,6 +28,11 @@
{ Processor independent part, shared with strings unit } {$i stringsi.inc }

+var
+ { widechar, because also used by widestring -> pwidechar conversions }
+ emptychar : widechar;external name 'FPC_EMPTYCHAR'; +
+
{ StrPas converts a PChar to a pascal string }

 function StrPas(Str: PChar): string;
@@ -56,8 +61,8 @@
   len : longint;
 begin
   Result:=nil;
-  if (p=nil) or (p^=#0) then
-   exit;
+  if (p=nil) then
+   ;
   len:=strlen(p)+1;
   Result:=StrAlloc(Len);
   if Resultnil then

(not committed since the same must be done for the wideroutines too.

Reply by email

Marco van de Voort
to Michael Van Canneyt: This argument can be applied to any OS older than 5 years :) Backwards compatibility…

In our previous episode, Michael Van Canneyt said:

Show quoted text 6 lines
> so it seems to be the emptychar story. Better fix that as well. > Unfortunately, FPC_emptychar is not exported from system. No, and you cannot use that directly, because in case of an error, the items in the argv array and the array itself are freed (or so I hope). The FPC_emptychar pointer should not be freed...

I found that out too. The patch I send earlier therefore only copies from it, but better maybe to eliminate the use of emptychar entirely.

fixing strnew() to allocate a single #0 on the heap is probably best.

strnew uses stralloc which in turn can only be disposed with strdispose. (prefixes 4 bytes length and futhers the pointer) In theory one can make thus an exception in strdispose too, but IMHO not worth it.

Reply by email

Sven Barth
to Michael Van Canneyt: This argument can be applied to any OS older than 5 years :) Backwards compatibility…
"Michael Van Canneyt" wrote 22 lines
On Thu, 7 May 2015, Marco van de Voort wrote: > In our previous episode, Michael Van Canneyt said: >>> >>> >>> Since NIL is a termination of an array of pchar in C that is not ok. >> >> >> if that were the case, argc would not have been introduced, >> which is why I doubt the use of this argument ? > > > Where is argc on the calling side? In the parameters of ExecVE ? Right. > >> C code that regards nil as the last element of the argv array is just >> wrong. > > > IMHO *nix is not terribly well designed. Probably the multitude of

versions

Show quoted text 6 lines
> and being interwoven with C prohibited doing massive cleanups. This argument can be applied to any OS older than 5 years :) Backwards compatibility probably prevents any OS from being considered

'well designed'.

In our company's OS we shuffle around quite frequently to improve the design and it's older than 5 years already. But then again we don't have any users except ourselves to care for currently... ^^

Regards,
Sven

Reply by email

Jonas Maebe
to Marco van de Voort: In our previous episode, Michael Van Canneyt said: No, strnew, since it is not delphi…
Marco van de Voort wrote 11 lines
Index: syspch.inc =================================================================== --- syspch.inc (revision 30815) +++ syspch.inc (working copy) @@ -28,6 +28,11 @@ { Processor independent part, shared with strings unit } {$i stringsi.inc } +var + { widechar, because also used by widestring -> pwidechar conversions } + emptychar : widechar;external name 'FPC_EMPTYCHAR';

FPC_EMPTYCHAR is for internal compiler usage. Importing it in other units does not seem like a good idea, especially since it only helps you save two bytes.

Jonas

Reply by email

Marco van de Voort
to Jonas Maebe

In our previous episode, Jonas Maebe said:

Show quoted text 7 lines
> +var > + { widechar, because also used by widestring -> pwidechar conversions } > + emptychar : widechar;external name 'FPC_EMPTYCHAR'; FPC_EMPTYCHAR is for internal compiler usage. Importing it in other units does not seem like a good idea, especially since it only helps you save two bytes.

(See my next message in the thread, I was never going to commit this)

Reply by email