Gettext without a filesystem - c

For an embedded system with GUI, we are using our custom translation system. The strings are stored in the code ROM of a microcontroller.
Currently we have up to 10 languages and about 400 translated strings (varies depending on the product variant).
Our current system is rather cumbersome and I believe that gettext would be a better solution.
As far as I understand gettext, it requires the use of bindtextdomain to set the directory containing the compiled translations files (*.mo).
Is there a way to instead read the translation from memory? That is I would like to include the compiled *.mo files in the binary, and set up gettext to use these. Alternatively, the translation data would be stored in a data EEPROM without a filesystem.
Or can you recommend a different translation system for use in a microcontroller system (16 or 32 bit, 256 to 512 kbyte ROM) with a C interface?
Edit: I should add that being able to maintain translations apart from the microcontroller firmware would be a reason to switch to gettext. The appropriate translation data would be loaded by the user with a configuration software that we already supply with our systems.

This is what I would do: I would include the binary ".mo" in constant variables in the code. You can write a simple converter from binary to a char array and have that ".mo" file compiled inside your program. You would have an array of ".mo" file data, each with a different language.
I would modify libintl sourcecode to access one of those arrays. Check the file loadmsgcat.c, the function _nl_load_domain. See there how it tries to use mmap() (so it's prepared to have everything in memory). Just add some code there to decide which element of your ".mo" array to use based on the language requested.
I haven't tried this, but this is what I would try given your situation. It doesn't look too hard.

Related

Creating different versions of .bin file in stm32cubeide

Context
I'm currently working on a firmware for a STM32F411CEU6, using STM32CubeIDE, I'm going to be programming several UC's, everyone of them is going to have an ID (a 32 bit unsigned number), this number is static and it will never be change in his lifespan, we are a small team but maybe we will have to program a few hundred of these devices, so changing the value associated whit that ID in the code manually will be kinda exhausting, and time consuming, so, my question is:
¿Is there a way to compile different versions of firmware so it generate several .bin files, each one whit the only difference that this single constant change?
¿Is there a way to automate this process?
What have I thought
I have thought on defining this constant (and other constants if I have to) on a header file, then use something like Python to make different versions of the code, but then I would have to open every project or workspace and still have to compile and produce every .binfile manually, ¿Is there a way to produce the .bin file from python (using the STM32CubeIDE), or something like that?
Additional information
Working on a STM32F411CEU6
Using STM32CubeIDE
I have basic knowledge in python C++
Medium-advance knowledge in C
Thanks in advance!
Any help would be very much appreciated
Here are a few ideas.
The STM32F411 chip is pre-programmed (by STMicro at the factory) with a 96-bit unique device ID. Perhaps you can use the device's unique ID for your purposes rather than creating and assigning your own ID value. See Section 24.1 of the reference manual. This seems much safer than trying to create and manage a different bin file for each ID value.
If you really want your own custom ID value, then program the ID value separately from the firmware bin file so that you don't need to create/manage different bin files for each unit. Write the program so that the ID value is at a known fixed address in ROM. Use the linker scatter file to reserve that address for the ID value. Program the ROM of each unit in two steps, the bin file and the ID value.
If you really want to incorporate the ID value into the bin file then you can use a tool such as srec_cat.exe to concatenate bin (also hex or srec) files. It's very versatile and you should study the man page. One example of how you could use this tool is this: In the source code for your program, declare your unique ID value a constant pointer to a constant value located at a fixed address in ROM beyond the end of the ROM consumed by the bin file. Build the bin file like normal. Then run srec_cat.exe to concatenate the unique ID value to the bin file with the appropriate offset. You could write a script to do this repeatedly for each unique ID value. Perhaps this script runs as a post-build action from the IDE. This solution could work but it seems like a maintenance nightmare to ensure the right bin file gets programmed onto the right device.
If using a hex file is an option, you could avoiding the need for re-compilation like so:
Reserve some flash space outside of your program (optionally configure the linker script to make sure no data is placed in that section).
Use a python script to generate intel hex data with the required ID placed in the reserved location.
Simply concatenate the two hex files and program as usual. I tested this with STM32 ST-LINK Utility / STM32CubeProgrammer.
To generate the hex data, you can use the intelhex package. For example:
import struct
from intelhex import IntelHex
from io import StringIO
ID_FLASH_ADDRESS = 0x8020000
hex_data = StringIO()
ih = IntelHex()
ih.puts(ID_FLASH_ADDRESS, struct.pack('<I', chip_id))
# Output data to variable
ih.write_hex_file(hex_data)
# Get the data
hex_data.getvalue().encode('utf-8')
Notes:
See the struct documentation for the meaning of '<I'.
I output the data to a variable, but you could also write directly to a file. See intelhex documentation.

How can I convert an .abs or .s19 to a C file?

I am trying to run some MC9S12DP256 example files, but I want to see the code to understand it. Are there any ways to convert a .s19 or .abs file to a C code?
An ".s19" or an ".abs" file contains mainly the machine code of the application. The source code of it is not included, independent of the language used to write it. Even if it were written in assembly language, all symbolic informations and comments are excluded.
However, you can try to de-compile the machine code. This is not a trivial or quick task, you need to know the target really well. I did this with software for other processors, it is feasible for code up to some KB.
These are the steps I recommend:
Get a disassembler and an assembler for the target processor, optimally from the vendor.
Let it disassemble the machine code into assembly source code. You might need to convert the ".s19" file into a binary file, one possible tool for this is "srecord".
Assemble the resulting source code again into ".s19" or ".abs", and make sure that it generates the same contents as your original.
Insert labels for the reset and interrupt entry points. Start at the reset entry point with your analysis.
Read the source code, think about what it does.
You will quickly "dive" into subroutines that execute small functions, like reading ADC or sending data. Place a label and replace the numerical value at the call sites with the label.
Expect sections of (constant) data mixed with executable code.
Repeat often from point 3. If you have a difference, undo your last step and redo it in another way until you produce the same contents.
If you want C source, it is commonly much more difficult. You need a lot of experience how C is compiled into machine code. Be aware that variables or even functions are commonly placed in another sequence than they are declared. If you want to go that route, you usually also have to use the exact version of the compiler used to generate the original machine code.
Be aware that the original might be produced with any other language.

Create a fixed size section with gcc and place values in it

I need to embed a binary file within an executable generated with gcc on Linux, to be executed in the host (not in a separated device).
In addition, I want to be able to change that binary content externally by using obcjcopy --update-section.
I could do that with __attribute__(("section")), but the problem is that the mentioned binary file might have different sizes at different moments, so I want to allocate a section of a fixed maximum size. Thus, I can update slightly bigger/smaller binaries in the future.
Apart from the above, I would like to give a default value to that particular section at build time (a predefined binary file that is available at build time).
This can be done with a linker script. However, as far as I understand, I would need to modify the OS default linker script, what I want to avoid.
The only thing that comes to my mind is to create an array on that section with a fixed size, using the first bytes for allocating the default binary file and padding the rest with 0xFF's for instance.
Is there a better way to do this?
As ikegami has mentioned, it's enough to specify the maximum size of the array and then initialise the values you need.

Create a C program of size 100 bytes with Visual Studio

I want to write a C application program which upon building will create an executable of size 100 bytes or less.
Even if I create a simple C program with just an empty main(), my output file becomes 11KB on Visual Studio 2015. Is there a way to tell VS not to include any default libs which will reduce my executable size. Or is there any other way to reduce the executable file size?
A sensible Win32 executable cannot be less than some hundred bytes in size: What is the smallest possible Windows (PE) executable?
You can however write a plain old COM executable, which can only be run on x86-Windows. You would need appropriate toolchains: Looking for 16-bit c compiler for x86
You can create an executable with the text section (i.e. the section that has the executable code in it) of less than 100 bytes for a hello world console output, but the .EXE file size will be larger because it needs to have a valid PE format structure, and that format requires quite a bit of padding. /NODEFAULT will of course give you errors. You'll then have to reimplement whatever's missing, usually making things no-op, and you'll need to use link-time code generation so that all the calls to the empty functions get removed (as well as the functions themselves). You'll also need to find compiler flags that disable all "cool" features. E.g. to make the compiler stop emitting buffer security checks (__security_check_cookie & al.), provide the /GS- option.
You'll probably need to use a custom tool to completely strip the .EXE file from unnecessary PE cruft that VS linker emits. And your executable will still be runtime-linked with at least KERNEL32.DLL, since without that you won't be able to do anything useful. If you're brave, you could use NTDLL.DLL (i.e. the native API) directly, but that will probably need more than 100 bytes of code to.
Your executable will also need to be targeting the 32 bit architecture; 64-bit one will be about 25% larger (at such small section sizes to start with).
It's a nice challenge.

Generating load time serial number for PCB application

I am trying to generate an incrementing value at load time to be used to "serialize" a PCB with a unique code value. Not an expert in ld or preprocessor commands, so looking for some help.
The value will be used in a unique ID for each board that the code is loaded on and will also be used as a counter for boards in the field.
I have no preconceived idea of how I might accomplish this, so any workable answer to get me started, including a pre-preprocessor macro is fine. In my olden days, I recollect adding a couple lines to the linker file that would accomplish this, but I have been unable to resurrect that information anywhere (including my brain's memory cells).
The simpler the answer, the better.
My solution to the problem was remarkably simple.
The binary contained
const char *serial = "XY-00000";
I then wrote a short program that boiled down to:
char uniqueserial [8];
/* Generate serial - this was an SQL call to the manufacturing DB */
char *array;
/* Read binary into array */
memcpy(memmem(array, "XY-00000",8), uniqueserial,8);
/* Write array to temp bin file for flashing */
Depends on the serial template string being unique in the binary. Use strings command to check. I disable crc protected object files due to taste. I like my embedded binaries being exact memory dumps.
The linker is not the right place for two reasons:
the executable can be loaded with the same id in several devices, making your approach void.
You should have to link the executable for each device you are programming, which poses an spent of cpu resources.
The best place is to patch the executable at loading time with the serial number.
Select a data patern as token to initialize your variable with the device id (a pattern difficult to happen elsewhere in your program binary) and initialize your serial number variable to that data pattern (better if you do it statically initializing an array variable or something similar)
Make a program to be executed on each download to device that search for the pattern in the executable file, before loading the binary program into the device and writes the correct value to be programmed into the device (beware that you are patching a binary, so you cannot think on variable lenght strings or the like, that can trash all the work made by the linker)
Once patched the binary executable, you can download it to the device.
Another solution is to reserve a fixed area in your linker script for all this kind of information. Then, put all your device information variables there. Then get the exact positions in rom for the individual variables and include the proper data in the loaded image. In this case, the linker is your friend, reserving some fixed segment in your device's rom allocated for storing the device's individual data (you can put there mac addresses, serial numbers, default configuration, etc.)

Resources