[Q] Possible to access DS carts and 3DS carts from the same homebrew app?

Discussion in '3DS - Homebrew Development and Emulators' started by LeifEricson, May 10, 2016.

  1. LeifEricson
    OP

    LeifEricson Coming Soon™

    Member
    214
    166
    Jun 22, 2012
    United States
    New York, USA
    Hey all,

    I'm working on a sort of interesting project (details to be revealed later) which can interface with not only 3DS game carts, but DS game carts as well. I've managed to implement DS cart functionality successfully using some of TWL Save Tool's code, but it seems that I cannot get both 3DS and DS support working at the same time. I want the user to be able to pick which type of cart at the start of the program.

    Is this perhaps because of the rsf file (it's CIA only at the moment), which I've noticed needs a few "TWL" flags to be set for DS compatibility? Or is it just something in my code? (I've tried taking code directly from a few 3DS save managers but although they can read the cartID, any attempt to read data from the cart results in nothing happening, but strangely no errors.)

    It's strange considering I'm directly using code from other save managers, the DS reading is working, but not the 3DS reading. I can try taking the rsf from it as well, but this of course would then break DS compatibility.
     
    Drakia likes this.
  2. Bedel

    Bedel The key of the blade

    Member
    999
    347
    Oct 28, 2015
    I don't think it is possible, but I don't know that much. Let's just speculate why it'd not work.
    Once you use the TWL, it enters in DSi mode (I don't know if this is wright), so the 3DS is no longer ablible to use or read 3DS games. If this is the case, then maybe you should separate the code in more modules. Maybe not use anything from TWL if it's not really needed. I don't know.
    I hope this cas be usefull, gl with your job.
     
  3. Slashcash

    Slashcash GBAtemp Fan

    Member
    334
    461
    Oct 15, 2015
    Italy
    It SHOULD be possible. Probably we can tell you more if you show us the source code!

    Of course it should be possible from a cia. The .3dsx won't work unless you boot under a process with can access both save and twl save
     
    Last edited by Slashcash, May 10, 2016
  4. LeifEricson
    OP

    LeifEricson Coming Soon™

    Member
    214
    166
    Jun 22, 2012
    United States
    New York, USA
    Here's my main as of now. It's pretty sloppy as I didn't implement a sort of proper state management class, but at the moment I'm solely focusing on getting working code before making it look pretty. Main interest should be the cartManager() call, which is almost directly copied from JKSM. It's also not really working as pasted right now but that's because I'm in the middle of switching code from PCHex++ (which I tried just because its filesystem code is pretty cleaned up), but it ended up not working so I'm in the process of going back to using JKSM's code.

    EDIT: I also think I should mention that PCHex++'s code was able to read the cartID successfully and has its own error handling which never produced any errors, yet still resulted in an empty array.

    Code:
    #include <3ds.h>
    #include "twl/TWLCard.h"
    #include "twl/TWLLoad.h"
    #include "jksm/cart.h"
    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <string>
    #include <sstream>
    #include <unistd.h>
    #include <stdio.h>
    #include <cstring>
    using namespace std;
    
    // Override the default service init/exit functions
    extern "C" {
        void __appInit() {
            // Initialize services
            srvInit();
            aptInit();
            gfxInitDefault();
            hidInit();
            fsInit();
            sdmcInit();
            pxiDevInit();
            consoleInit(GFX_TOP, NULL);
        }
    
        void __appExit() {
            // Exit services
            pxiDevExit();
            sdmcExit();
            fsExit();
            hidExit();
            gfxExit();
            aptExit();
            srvExit();
        }
    }
    
    int main() {
        //ENVIROMENT INITIALIZATION
        string gameID = "";
        int game = 0;
        int state = 0;
        bool updateTop = true;
        vector<uint8_t> save(600000);
     
        // State 0 variables
        vector<string> st0choices;
        st0choices.push_back("NDS Pokemon Cartridge");
        st0choices.push_back("3DS Pokemon Cartridge");
        st0choices.push_back("SD Card Save File");
        int st0sel = 0;
     
        //MAIN LOOP
        while( aptMainLoop()) {
            hidScanInput();
            auto keys = hidKeysDown();
         
            if(keys & KEY_START) break;
         
            if(keys & KEY_A) {
                updateTop = true;
                if (state == 0) ++state;
            }
         
            if(keys & KEY_DDOWN) {
                updateTop = true;
                if (state == 0) { if(st0sel < st0choices.size()-1)++st0sel; else st0sel = 0; }
            }
            if(keys & KEY_DUP) {
                updateTop = true;
                if (state == 0) { if(st0sel > 0)--st0sel; else st0sel = st0choices.size()-1; }
            }
         
            if (updateTop) {
                consoleClear();
                updateTop = false;
                // Main menu state
                if (state == 0) {
                    cout << "Choose SOURCE game type:\n\n";
                    for (int i = 0; i < st0choices.size(); ++i) {
                       if (i == st0sel) cout << "\x1b[47;30m"+st0choices[i]+"\x1b[40;37m" << endl;
                       else cout << st0choices[i] << endl;
                    }
                }
                // Save reading state
                else if (state == 1) {
                    // NDS cart
                    if (st0sel == 0) {
                // Stripped down TWL Tool main(), returns a u8 vector of loaded save and currently works
                        save = twlLoad(gameID);
                        if (gameID.size() == 0) break;
                        updateTop = true;
                        ++state;
                    }
                    // 3DS cart
                    else if (st0sel == 1) {
                        // Stripped down JKSM cartManager(), uses JKSM functions to write save to file, then loads file back into u8 vector, please note that the written output file is 0 bytes and the vector becomes empty. Also note that PCHex++'s functions to read directly to a char buffer were tested and also returned empty arrays.
                        cartManager(save);
                    }
                    // SD Save
                    else if (st0sel == 2) {
    
                    }
                }
                // Debug state
                else if (state == 2) {
                    cout << "Game ID: " << gameID << endl;
                    if (save.size() > 200) {
                        for (int i = 0; i < 200; ++i) {
                            cout << hex << (int)save[i] << " ";
                        }
                    }
                    else cout << "Error loading save file!!";
                }
            }
            gfxFlushBuffers();
            gfxSwapBuffers();
            gspWaitForVBlank();
        }
     
     
        //ENVIROMENT CLEANING
        return 0;
    }
     
    Last edited by LeifEricson, May 10, 2016
  5. Uziskull

    Uziskull Picture may not be real

    Member
    269
    179
    Nov 15, 2015
    Portugal
    Somewhere, probably
    Someone's finally working on a homebrew PokéTransfer app. Nice.
     
  6. daxtsu

    daxtsu GBAtemp Guru

    Member
    5,546
    3,956
    Jun 9, 2007
    Antarctica
    @TuxSH would probably know, since he wrote the TWL Save Tool. Thoughts, Tux?
     
  7. TuxSH

    TuxSH GBAtemp Advanced Fan

    Member
    612
    994
    Oct 19, 2015
    France
    No it doesn't.
     
  8. Joom

    Joom  ❤❤❤

    Member
    4,305
    2,948
    Jan 8, 2016
    United States
    HE HATH SPOKANE

    On a serious note, I kinda figured the same thing; using TWL flags goes into a certain mode that doesn't read 3DS data properly. I was also thinking of a way to hot swap between modes if that were the case, but I guess it's not.

    Also, I kinda giggled at the idea of Leif Ericson writing code. Hinga hurga horda.
     
    Last edited by Joom, May 10, 2016
  9. TuxSH

    TuxSH GBAtemp Advanced Fan

    Member
    612
    994
    Oct 19, 2015
    France
    Try stripping those flags ... ?
     
  10. Slashcash

    Slashcash GBAtemp Fan

    Member
    334
    461
    Oct 15, 2015
    Italy
    Given that your .rsf has all the correct flags uncommented (you could look at PCHex++'s rsf file, but i don't think this is the problem since PCHex++'s code would return an error when opening the save archive) i can't see nothing wrong in the code you posted because it is just gui code.

    Would you mind showing the cartManager() function and his signature? There should be something wrong there.

    As a side note, i don't think this should be the problem as you seem pretty aware of what you are doing, but just in case, are you possibly doing

    Code:
    void callManager(std::vector<uint8_t> buffer)
    
    Because if that's the case the reason why you are getting an empty vector is pretty obvious (and it would explain why the nds reading is working instead)

    of course the correct signature is:

    Code:
    void callManager(std::vector<uint8_t> &buffer)
    
    (PS: if you need some help in interpreting PCHex++ filesystem code you can pm me for my skype id)

    [EDIT]In all honesty i never tested if having both the twl and the save flag stripped down causes any problem, i would say no but who knows...
     
    Last edited by Slashcash, May 10, 2016
  11. LeifEricson
    OP

    LeifEricson Coming Soon™

    Member
    214
    166
    Jun 22, 2012
    United States
    New York, USA
    I PM'd you, I really appreciate it Slashcash. I'll share any code you'd like to see with you over Skype.
     
  12. LeifEricson
    OP

    LeifEricson Coming Soon™

    Member
    214
    166
    Jun 22, 2012
    United States
    New York, USA
    Quick update, switched back to PCHex++ code, turns out I still get no error codes. Even tried using your .rsf. The code below never enters the errorLoop() function, but instead goes to state 2 which was shown earlier, but complains about an empty save vector. Here's what my relevant snippet looks like now:

    Code:
    else if (state == 1) {
                    // NDS Card
                    if (st0sel == 0) {
                        save = twlLoad(gameID); // Stripped down TWL Save Tool's main()
                        if (gameID.size() == 0) { errorLoop("twlLoad", 1); break; }
                    }
                    // 3DS Card
                    else if (st0sel == 1) {
                        // Direct code from PCHex++ (unmodified)
                        int ret = FileSystem::romFsInit();
                        if (ret) { errorLoop("romFsInit", ret); break; }
                        ret = FileSystem::initialize(-1, FileSystem::CART); // This returns 0x113 every time...
                                                                      // (game set to -1 since always uses CART condition)
                        if (ret) { errorLoop("FS::initialize", ret); break; }
                        Savefile test;
                        ret = test.loadSaveFile();
                        if (ret) { errorLoop("loadSaveFile", ret); break; }   
                        save = test.getSaveVector(); // Custom method     
                    }
                    // SD Save File
                    else if (st0sel == 2) {
    
                    }
    
    ...
    EDIT: Here's the getSaveVector method I added to savefile.cpp:

    Code:
    std::vector<uint8_t> Savefile::getSaveVector() {
        std::vector<uint8_t> saveVec(sizeof(save));
        memcpy(&saveVec[0], save, sizeof(save));
        return saveVec;
    }
    — Posts automatically merged - Please don't double post! —

    I tried using PCHex++'s code and its .rsf file directly (which has no TWL flags but all the right "3ds" cart flags) and still no luck.
     
    Last edited by LeifEricson, May 10, 2016 - Reason: Derp'd and realized there's no return codes as of now