Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Selecting file for printng with M23 by it's long filename does not work #25497

Closed
1 task done
eduard-sukharev opened this issue Mar 11, 2023 · 4 comments · Fixed by #25540
Closed
1 task done

Comments

@eduard-sukharev
Copy link
Contributor

Did you test the latest bugfix-2.1.x code?

Yes, and the problem still exists.

Bug Description

Even with LONG_FILENAME_HOST_SUPPORT and LONG_FILENAME_WRITE_SUPPORT defines, selecting a file for printing with M23 by the long file name does not work.

Bug Timeline

No response

Expected behavior

Selecting a file for printing with M23 works

Actual behavior

Selecting a file by it's long filename fails

Steps to Reproduce

  1. Insert SD card with a file that has long filename (non-DOS compatible), e.g. longfilename.gcode
  2. In Serial console issue M21 command
  3. In Serial console issue M20 L command. Verify that the file is there and reported with both DOS filename and Long filename (LONGFI~1.GCO and longfilename.gcode)
  4. In Serial console issue M23 longfilename.gcode to select the file

Version of Marlin Firmware

bugfix-2.1.x

Printer model

No response

Electronics

No response

Add-ons

No response

Bed Leveling

None

Your Slicer

None

Host Software

Pronterface

Don't forget to include

  • A ZIP file containing your Configuration.h and Configuration_adv.h.

Additional information & file uploads

I have added a bunch of DEBUG_ECHO* calls that mostly duplicate code comments, into SdBaseFile.cpp, inside the method with following signature:

// open with filename in dname and long filename in dlname
bool SdBaseFile::open(SdBaseFile *dirFile, const uint8_t dname[11]
    OPTARG(LONG_FILENAME_WRITE_SUPPORT, const uint8_t dlname[LONG_FILENAME_LENGTH])
  , uint8_t oflag
)

and here's the sample serial console log:

ttyACM0 21°> M20 L
SENDING:M20 L
Begin file list
LONGF~1.GCO 758868 LONGF~1.GCO
LONGFI~1.GCO 902501 longfilename-1.gcode
LONGFI~2.GCO 879788 longfilename-2.gcode
SAMPLE~1.GCO 921715 sample_long_name.gcode
TEMP.GCO 444974 TEMP.GCO
End file list
ttyACM0 21°> M23 /longfilename-1.gcode
SENDING:M23 /LONGFILENAME-1.GCODE
Now fresh file: /LONGFILENAME-1.GCODE
>>> diveToFile  X0.00 Y208.00 Z0.00
 path = '/LONGFILENAME-1.GCODE'
 CWD to root: 0x200032D4
 startDirPtr = 0x200032D4
 final workDir = 0x200032D4
 returning string LONGFILENAME-1.GCODE
<<< diveToFile  X0.00 Y208.00 Z0.00
>>> SdBaseFile::open()  X0.00 Y208.00 Z0.00
 dname: LONGF~18GCO
 reqEntriesNum: 3 lfnNameLength: 20
 search for file
/  absolute index position: 0
  p->name: PRINT
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
/  absolute index position: 1
  p->name: LONGF~1 GCO
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
/  absolute index position: 2
  p->name: B1
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
       isDirLFN(p)
       lfnSequenceNumber: 2
        Check checksum for all other entries with the starting checksum fetched before
         Set chunk of LFN from VFAT entry into lfnName
         LFN found?:          lfnFileFound: 0
/  absolute index position: 3
  p->name: l
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
       isDirLFN(p)
       lfnSequenceNumber: 1
        Check checksum for all other entries with the starting checksum fetched before
         Set chunk of LFN from VFAT entry into lfnName
         LFN found?:          lfnFileFound: 0
/  absolute index position: 4
  p->name: LONGFI~1GCO
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
/  absolute index position: 5
  p->name: B2
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
       isDirLFN(p)
       lfnSequenceNumber: 2
        Check checksum for all other entries with the starting checksum fetched before
         Set chunk of LFN from VFAT entry into lfnName
         LFN found?:          lfnFileFound: 0
/  absolute index position: 6
  p->name: l
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
       isDirLFN(p)
       lfnSequenceNumber: 1
        Check checksum for all other entries with the starting checksum fetched before
         Set chunk of LFN from VFAT entry into lfnName
         LFN found?:          lfnFileFound: 0
/  absolute index position: 7
  p->name: LONGFI~2GCO
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
/  absolute index position: 8
  p->name: Ba
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
       isDirLFN(p)
       lfnSequenceNumber: 2
        Check checksum for all other entries with the starting checksum fetched before
         Set chunk of LFN from VFAT entry into lfnName
         LFN found?:          lfnFileFound: 0
/  absolute index position: 9
  p->name: s
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
       isDirLFN(p)
       lfnSequenceNumber: 1
        Check checksum for all other entries with the starting checksum fetched before
         Set chunk of LFN from VFAT entry into lfnName
         LFN found?:          lfnFileFound: 0
/  absolute index position: 10
  p->name: SAMPLE~1GCO
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
/  absolute index position: 11
  p->name: TEMP    GCO
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     useLFN
      !lfnFileFound
/  absolute index position: 12
  p->name:
  Check empty status: Entry empty
<<< SdBaseFile::open()  X0.00 Y208.00 Z0.00
open failed, File: LONGFILENAME-1.GCODE.
ttyACM0 21°> M23 /LONGFI~1.GCO
SENDING:M23 /LONGFI~1.GCO
Now fresh file: /LONGFI~1.GCO
>>> diveToFile  X0.00 Y208.00 Z0.00
 path = '/LONGFI~1.GCO'
 CWD to root: 0x200032D4
 startDirPtr = 0x200032D4
 final workDir = 0x200032D4
 returning string LONGFI~1.GCO
<<< diveToFile  X0.00 Y208.00 Z0.00
>>> SdBaseFile::open()  X0.00 Y208.00 Z0.00
 dname: LONGFI~1GCO
 reqEntriesNum: 1 lfnNameLength: 0
 search for file
/  absolute index position: 0
  p->name: PRINT
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     !useLFN
/  absolute index position: 1
  p->name: LONGF~1 GCO
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     !useLFN
/  absolute index position: 2
  p->name: B1
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     !useLFN
/  absolute index position: 3
  p->name: l
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     !useLFN
/  absolute index position: 4
  p->name: LONGFI~1GCO
  Check empty status: Entry not empty
    Reset empty counter
    Search for SFN or LFN?
     !useLFN
      fileFound: 1
<<< SdBaseFile::open()  X0.00 Y208.00 Z0.00
File opened: LONGFI~1.GCO Size: 902501
File selected
ttyACM0 21°>

As can be clearly seen in

>>> SdBaseFile::open()  X0.00 Y208.00 Z0.00
 dname: LONGF~18GCO

the short filename composed to lookup the file by was wrong (and presumably pretty much random), which didn't match the actual short name of a file and thus selecting a file failed.

@eduard-sukharev eduard-sukharev changed the title [BUG] Selecting file for printng by LFN does not work [BUG] Selecting file for printng with M23 by it's long filename does not work Mar 11, 2023
@eduard-sukharev
Copy link
Contributor Author

Further debugging reveals following: in a file Marlin/src/sd/SdBaseFile.cpp a function with signature bool SdBaseFile::open(SdBaseFile *dirFile, const uint8_t dname[11] OPTARG(LONG_FILENAME_WRITE_SUPPORT, const uint8_t dlname[LONG_FILENAME_LENGTH]), uint8_t oflag) actually scans VFAT sequences to compose a complete LFN by matching LFN checksums, which means that it supposed to not care if the generated short dosname is random. The issue with mismatching filenames remains unresolved, though, as I still cannot understand why exactly that happens

@eduard-sukharev
Copy link
Contributor Author

The issue seem to be that lfn comparison is done like this:

if (!strncasecmp((char*)dlname, (char*)lfnName, lfnNameLength)) lfnFileFound = true;

and while dlname and lfname are both uint8_t and have same length, dlname content is encoded as single-byte chars string (ASCII), while lfname contains two-byte chars encoding (UTF-16LE).

@thisiskeithb
Copy link
Member

Closing since you've opened a PR.

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked and limited conversation to collaborators May 18, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants