Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Autres questions


Index du Forum » Autres questions » One specific Bfile_WriteFile call only writing FF?
Prgmprotogen Hors ligne Membre Points: 45 Défis: 0 Message

One specific Bfile_WriteFile call only writing FF?

Posté le 20/03/2026 06:50

Hello folks of Planet Casio,
I'm having some really odd troubles with file manipulation, using the official Casio 9860G SDK and libraries.
My game has a saving feature that saves a bunch of the player's stats, along with the level data (since it gets modified during gameplay and is extremely important). In the code, I create the save file (or re-create it if it already exists) in Storage Memory, open it, and then make a bunch of consecutive write calls using Bfile_WriteFile(); it writes each of the relevant stats and the player's position, writes the level/floor data, then closes the file. In a separate function, I load the data from the file into the variables using a process similar to saving, except I use Bfile_ReadFile().
This has worked great for me for quite a while, but after working on a few other things I realized that my game crashed when trying to load a save. I tried messing around, and changing it to save to the emulator's virtual SD card inexplicably fixed the issue. However, I wanted it to save to storage memory, so that solution wouldn't work for me. I figured out the crash was caused by unusual data trying to be read and interpreted as floor tiles, and added a line of code to handle such errors. I then tried reading Memory in the emulator (and using a hex editor on the actual file generated by hardware), and found that the level data was encoded all as hexadecimal FF. The player stat data was perfectly fine, and the game could load that part of the data properly, but the level data was messed up (and only during the saving process). It's definitely not being changed in memory, just in the final saved file.
If it helps, I'm passing the address of a 3D array containing each floor of the level.
The array is: char floors[7][8][8];
The write call is: writeItem(&floors, (totalFloors * 64));
And this is the writeItem function:
void writeItem(void* itm, int len) {
    Bfile_WriteFile(fHeader, itm, len);
}

This code might be a little incorrect or amateur-ish, but it has worked pretty well in the past.
I have absolutely no clue what change could be causing this, this has left me utterly bewildered (especially since writing to an SD card works fine somehow??? ). Does anybody have an idea as to what's causing this, or how it could be fixed? Any help would be greatly appreciated!


Prgmprotogen Hors ligne Membre Points: 45 Défis: 0 Message

Citer : Posté le 20/03/2026 06:52 | #


I should add, the variable fHeader is the header returned from Bfile_OpenFile. It's declared outside of the functions its used in.
Lephenixnoir En ligne Administrateur Points: 25749 Défis: 174 Message

Citer : Posté le 20/03/2026 09:30 | #


You should know that FF is the initial value of all the bytes in the file, because of the Flash. When created, the file consists of all FF and when writing these bytes turn into their final value.

So it may be that the write just fails. Can you catch and print the return value of the appropriate WriteFile call? Can you also check, just in case, that itm definitely contains the values you expect?

Also note that on the older, in-house filesystem (before Fugue) writing an odd number of bytes is a big no-no, it will mess up the file pretty dramatically IIRC, so make sure all the writes that you perform are of even length.
Mon graphe (27 Juin): (MQ || Rogue Life) ; serial gint ; passe gint 3 ; Azur ; ...) || (shoutbox v5 ; v5)
Prgmprotogen Hors ligne Membre Points: 45 Défis: 0 Message

Citer : Posté le 20/03/2026 16:31 | #


Oh, checking it, it returns -31 corresponding to IML_FILEERR_DEVICEERROR. For good measure, I checked the return value of the previous writeItem (which is writing an int), and that returns a positive value of 4.
From my personal attempts to solve this, it seems that there's something about the floors array specifically that causes it to fail.
I've tried writing each floor tile byte-by-byte using a couple different methods, and the best I've gotten is writing the first top-left floor tile of the first floor correctly. I've also tried passing in &floors[0] instead of just &floors, but that changed nothing. And to be safe, I tried adding some extra error handling code to avoid repeatedly deleting and recreating the save file from scratch, but even after running storage memory optimization that doesn't seem to fix the issue.
Also checking the value of itm when running the floors writeCall, it points exactly to the start of the floors array in memory.
Looking back over everything, it looks like everything currently uses either 4 bytes, or in the case of floors 7 * 64 or 448 bytes (and with 13 4-byte variables, that ends up being 500 in total for the file size). Should I be writing an amount that's a power of 2, like 512?

If it helps, the emulator calculator OS version is 01.03.0000, while my physical fx-9860GII's OS version is 02.00.0200
Lephenixnoir En ligne Administrateur Points: 25749 Défis: 174 Message

Citer : Posté le 20/03/2026 16:34 | #


Are you by any chance trying to write from an array that is not in RAM?
Mon graphe (27 Juin): (MQ || Rogue Life) ; serial gint ; passe gint 3 ; Azur ; ...) || (shoutbox v5 ; v5)
Prgmprotogen Hors ligne Membre Points: 45 Défis: 0 Message

Citer : Posté le 20/03/2026 16:42 | #


I don't think so, I'm writing from position 08101075 which should be in the RAM range, and other aspects of the game that modify the floors array still work.
I don't know if this matters, but I typically modify the floors array through a proxy pointer named currentFloor. The definition is: char (*currentFloor)[8][8] = &floors[0]; and whenever the player moves between floors, it's reassigned to &floors[currentFloorNum]. I'll try saving the data through the proxy to see if that changes anything.
Prgmprotogen Hors ligne Membre Points: 45 Défis: 0 Message

Citer : Posté le 20/03/2026 16:51 | #


Using the proxy is a bust. The best I've managed to get is writing the address of the currentFloor pointer and writing that plus some junk data. Whatever it is, it doesn't seem to like the floors array.
Lephenixnoir En ligne Administrateur Points: 25749 Défis: 174 Message

Citer : Posté le 20/03/2026 17:04 | #


Ah the floors array is unaligned. Align it.
Mon graphe (27 Juin): (MQ || Rogue Life) ; serial gint ; passe gint 3 ; Azur ; ...) || (shoutbox v5 ; v5)
Prgmprotogen Hors ligne Membre Points: 45 Défis: 0 Message

Citer : Posté le 20/03/2026 17:19 | #


This should align the the position of the array in RAM to a nicer, more fixed/chunked position, right? Sorry, I'm a bit of a noob so I've never heard of this haha, should I use something like _Alignof or _Alignas? And what value should I set the alignment to? I'm having trouble figuring out how I should structure it so that it compiles without errors.
Lephenixnoir En ligne Administrateur Points: 25749 Défis: 174 Message

Citer : Posté le 20/03/2026 17:56 | #


Yeah you want it to be at least 2-aligned (the Flash deals in 2-byte units), and the safest is to have it 4-aligned, as this is the largest natural unit that the calculator deals with.

The good standard way is indeed to do _Alignas(int), but that's a feature from C11, that the CASIO SDK doesn't support. There have been non-standard versions for super long, typically __attribute__((aligned(4))), but the SDK compiler doesn't support that either. The pure-C way to obtain the same result is to use a union:

union { int _align; char floors[7][8][8]; } u;

In a union all members are guaranteed to be allocated at the same address, and since the int requires 4-byte alignment, that address will be 4-aligned. However you must then refer to floors as u.floors, which is a bit annoying, but should be fine for at least a quick test of whether this fixes the bug.
Mon graphe (27 Juin): (MQ || Rogue Life) ; serial gint ; passe gint 3 ; Azur ; ...) || (shoutbox v5 ; v5)
Prgmprotogen Hors ligne Membre Points: 45 Défis: 0 Message

Citer : Posté le 20/03/2026 18:15 | #


With a quick implementation, it doesn't throw an error when loading a save anymore (and returns 448), and the variable is set up at 0810001C! Although for some reason the player position is reset to the top left upon loading, and it also only seems to save as all 0x00 now, even when hex-editing the floor data in the memory panel to replace a specific tile to 0x16.
I think I forgot to mention, but I hardcoded some level data into the floors array; would it be possible to use the union definition while also defining the hardcoded data? The compiler doesn't like when I try to define it in the union.
Lephenixnoir En ligne Administrateur Points: 25749 Défis: 174 Message

Citer : Posté le 20/03/2026 21:55 | #


For the initializer, this:

char floors[7][8][8] = { initializer };

sould become this:

union { int _align; char floors[7][8][8]; } u = { .floors = { initializer }};

However I vaguely remember designated initializers being a C99 feature, so not sure whether the SDK will support it.
Mon graphe (27 Juin): (MQ || Rogue Life) ; serial gint ; passe gint 3 ; Azur ; ...) || (shoutbox v5 ; v5)
Prgmprotogen Hors ligne Membre Points: 45 Défis: 0 Message

Citer : Posté le 20/03/2026 22:37 | #


Doesn't seem like it's supported, just got a couple of compiler errors.
I'll try and do some more research into how I might be able to align the array, or otherwise get it to fully and correctly read the union version of it.
This may be a stretch, but could I possibly allocate the memory for floors myself using a function like malloc()? Perhaps allocate it as the very first thing, then later on load in the level data into it?

By the way, thank you very very much for your help, this information has been extremely useful to me!
Lephenixnoir En ligne Administrateur Points: 25749 Défis: 174 Message

Citer : Posté le 21/03/2026 09:39 | #


I looked up the compiler docs for an align pragma, there's a pack pragma for structures (https://bible.planet-casio.com/common/renesas/rej10b0152_sh.pdf page 344) but setting "pack 4" doesn't forcefully align chars, so I think you don't have any easier option than a union, changing the type, or using malloc.

malloc is a good choice, btw. Just define your "floors constant" the way you defined floors so far, then do a memcpy into the malloc area.

For the record, malloc always returns maximally-aligned pointers (4-aligned on this machine) specifically because it doesn't know what data type you'll be storing in the buffer.
Mon graphe (27 Juin): (MQ || Rogue Life) ; serial gint ; passe gint 3 ; Azur ; ...) || (shoutbox v5 ; v5)
Prgmprotogen Hors ligne Membre Points: 45 Défis: 0 Message

Citer : Posté le 21/03/2026 17:40 | #


Sweet, if that's the case I might as well go with malloc. Thank you!
I'm having a few issues with System/TLB errors, but I think that's just because I'm referring to the pointer as an array when it doesn't know that I'm referencing an array (or doesn't know the dimensions, and therefore can't calculate how much to offset the pointer by). After all, adding a Sleep(5000) call after the memory assignment shows a blank screen without errors, proving that my malloc and memcpy calls aren't the issues. Hopefully it should be a simple albeit tedious fix of replacing all references to floor with a calculated version, probably through the use of a custom abstraction function.
If I can get it fully working, I'll give an update!
Lephenixnoir En ligne Administrateur Points: 25749 Défis: 174 Message

Citer : Posté le 21/03/2026 18:23 | #


Make sure you're not confusing char [7][8][8] with something like char ***
Mon graphe (27 Juin): (MQ || Rogue Life) ; serial gint ; passe gint 3 ; Azur ; ...) || (shoutbox v5 ; v5)

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
captcha
Rafraîchissez la page si vous souhaitez obtenir un nouveau CAPTCHA.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2026 | Il y a 175 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd