Thread: SD card write to sector

  1. #1
    Registered User
    Join Date
    May 2017
    Posts
    5

    SD card write to sector

    Hi all,

    I've been programming in Visual Studio 2015 - Windows Forms Managed C.

    What I'd like to be able to do now is write to an SD card by sector i.e. not just create files using the simple method. The reason for this is that I have created a small data logger which reads a command string from the SD card that instructs it which sensors/frequencies to use, which the user has to put into a small text file manually. I'd instead like an app to create the command string on the SD card directly by writing this to a specific sector which the PIC can access simply.

    I found a link on NERDKITS website, but I can't register or login there due to some web-safety issue (according to Chrome)

    They provide some nice simple code that shows how to read a sector and write a sector. Reading works fine, but writing doesn't, although no error is produced at all. Note that this is writing to the volume, not to a specific file. I adjusted the code to create a file rather than writing to the volume directly and that worked fine, it just won't write to a specific sector.

    Here's the code that's just not doing anything - If I have a text file with it's content sat at that exact offset (262144), the text file content appears in the console. It should modify to first 5 characters to "hello", save, flush buffer, close the file, and then re-read and display what's there. No change to the file content. If I open the file in Windows, that too shows no change to the file.

    Code:
        char buf[1024];
        long long offset = 262144;
        FILE *volume;
        volume = fopen("\\\\.\\j:", "r");
        if (volume)
        {
            setbuf(volume, NULL);
    
    
            if (_fseeki64(volume, offset, SEEK_SET) == 0)
            {
                size_t cb = fread(buf, sizeof(*buf), _countof(buf), volume);
                System::String^ bufd = gcnew System::String(buf);
                Console::WriteLine(bufd);
            }
            fclose(volume);
        }
    
        buf[0] = 'h';
        buf[1] = 'e';
        buf[2] = 'l';
        buf[3] = 'l';
        buf[4] = 'o';
    
        volume = fopen("\\\\.\\j:", "a");
        if (!volume)
        {
            Console::WriteLine("failed volume");
        }
        else
        {
            setbuf(volume, NULL);
    
    
            if (_fseeki64(volume, offset, SEEK_SET) == 0)
            {
                size_t cb = fwrite(buf, sizeof(*buf), _countof(buf), volume);
                fflush(volume);
            }
            else
            {
                Console::WriteLine("failed");
            }
    
    
            fclose(volume);
        }
    
        volume = fopen("\\\\.\\j:", "r");
        if (volume)
        {
            setbuf(volume, NULL);
    
    
            if (_fseeki64(volume, offset, SEEK_SET) == 0)
            {
                size_t cb = fread(buf, sizeof(*buf), _countof(buf), volume);
                System::String^ bufd = gcnew System::String(buf);
                Console::WriteLine(bufd);
                // Process the data
            }
            fclose(volume);
        }
    This code sits within a larger application which is executed at the click of a button.

    The application is run in Administrator Mode, which I hoped would solve the problem but...

    Any clue as to why no change is made to the file?

    Note the "lock" is off on the sd card :P

    Best,

    Jimbo

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    A couple of things spring to mind.

    1. Not all error paths lead to code which prints a diagnostic.

    2. opening in "a" mode seems odd. In append mode, all writes happen at the end, regardless of any seek positions.
    It seems to me the mode you want is "r+".

    Code:
            size_t cb = fread(buf, sizeof(*buf), _countof(buf), volume);
            System::String^ bufd = gcnew System::String(buf);
    Does the 2nd line assume that the first line has placed a suitable \0 somewhere in the buffer to mark the end of the string?
    If this is your assumption, then the code is broken.
    fread() does NOT append \0.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2017
    Posts
    5
    Hi Salem,

    Many thanks for getting back to me quickly on this.

    Aye, I've noticed that before, that things don't happen and there's no error. Annoying! :-)

    The opening in "a" mode is what they showed on the website (I forgot to send the link earlier: NerdKits - C program to read and write raw data on SD card (Everything Else) )

    I did try various other options after looking up fwrite syntax etc. including r+, but they fail to fopen the volume, resulting in the console reported "failed" or "failed volume".

    The bit of code you highlighted; it doesn't really matter too much about that, I'm just using that to view what it has written - it's after the fail, but surprisingly, it does work i.e. if the fopen mode is "a", it does print the first 1024 chars present at that offset.

    Open to further suggestions...

    Best,

    Jimbo

  4. #4
    Registered User
    Join Date
    May 2017
    Posts
    5
    I've since read that, since Vista/Windows 7, files/volumes must be locked (exclusive?) before they can be written to, else some other app' could potentially write to the same file/sector as my app. Not sure if this is the case as I did manage to create a new file with a modified version of the code above, but I've not written to an existing file (amending / "a").

    Does anyone have any idea of how to implement this into my code (including unlocking it at the end...) if this is the case?

    Best,

    Jimbo

  5. #5
    Registered User
    Join Date
    May 2017
    Posts
    5
    Hi all,

    To anyone that has been following this thread. I managed to cobble together enough from other sites to be able to read a sector, make a change, and then store that buffer back at the same sector (note that one has to set the file pointer, read the sector, and then reset the file pointer to the same spot again before writing - this is hopefully common sense but I should say it just in case). This is just to probe to me that I can change the content of a particular sector. Now the fun begins!!!

    I ended up getting rip of the fopen/fread/fwrite commands and used, much to everyone else's advice, createfile. I also had to lock the drive in order to gain write-access to the sectors. Still need to get the unlock working again; at the moment, I have to close the application for the SD card to appear in Windows Explorer, but that's not the end of the world.

    The text file starting at address (address not sector; sector number being offset/512) 262144 contained the start address of the text file I had previously placed on the SD card with "testtesttest123" in the file. After running this routine, the content of the text file read "helloesttest123".

    I should also point out that one of the stumbling points on this was that it didn't like it when I had the number of bytes to read as 1024 or 1023. As soon as a dropped this to 512, it started to work. More investigation required here.

    I'm nowhere near to being a pro-C programmer, but I somehow manage to stumble through! It's not a great deal of code here but it's enough to now allow me to do everything else I want to do.

    Note that j: is my SD card slot. Wo betide anyone who sets this to C: and starts writing to random sectors there!

    The code (that worked) in toto is:

    Code:
        char buf[600];  // Multiple of sector size
        long long offset = 262144;  // Sector-aligned offset
        
        BOOL bTest = FALSE;
        DWORD dwNumRead = 0;
        HANDLE hFile = CreateFile(
            L"\\\\.\\j:",
            (GENERIC_READ | GENERIC_WRITE),
            (FILE_SHARE_READ | FILE_SHARE_WRITE),
            NULL,
            OPEN_EXISTING,
            0,
            NULL
            );
    
    
        if (hFile == INVALID_HANDLE_VALUE)
        {
            Console::WriteLine("Failed to create drive access");
        }
        DWORD bytesReturned;
        
        BOOL retDevIoCtrl = DeviceIoControl(
            hFile,            
            FSCTL_LOCK_VOLUME, 
            NULL,            
            0,     
            NULL, 
            0, 
            &bytesReturned,
            NULL 
            );
    
    
        SetFilePointer(hFile, offset, 0, FILE_BEGIN);
        ReadFile(hFile, buf, 512, &bytesReturned, 0);
        
        buf[0] = 'h';
        buf[1] = 'e';
        buf[2] = 'l';
        buf[3] = 'l';
        buf[4] = 'o';
    
    
        SetFilePointer(hFile, 262144, 0, FILE_BEGIN); // FILE_BEGIN
        WriteFile(hFile, buf, 512, &bytesReturned, 0);
    
        CloseHandle(hFile);
    Best,

    Jimbo
    Last edited by JimboStlawrence; 05-30-2017 at 04:13 PM.

  6. #6
    Registered User
    Join Date
    May 2017
    Posts
    5
    To UNLOCK the drive, I simply had to close the file handle.

    Code:
        CloseHandle(hFile);

    Hope the above helps someone...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. sector per track
    By sunil21 in forum C Programming
    Replies: 1
    Last Post: 09-13-2003, 11:10 PM
  2. sector size
    By elad in forum C++ Programming
    Replies: 5
    Last Post: 07-28-2003, 06:03 AM
  3. Writing a boot sector. I must be mad...
    By SMurf in forum Tech Board
    Replies: 8
    Last Post: 03-19-2003, 02:07 PM
  4. Solving bad sector ....
    By beely in forum Tech Board
    Replies: 7
    Last Post: 03-17-2003, 08:22 AM
  5. Fix the boot sector?
    By KrAzY CrAb in forum Tech Board
    Replies: 4
    Last Post: 03-14-2003, 06:07 PM

Tags for this Thread