sharing SD-MMC_FATEngine with top-level spin and V2-WAV_DACEngine to Eliminate Redundant Objects
[edit]added Tags, clarified Discussion Title[/edit]
Greetings,
I've been using V2-WAV_DACEngine by Kwabena W. Agyeman, available on the Propeller Object Exchange. When I selected it, the object seemed to be the most appropriate one for me. Aside from small glitches every-so-often during playback of a large WAV file, it's perfect.
The V2-WAV_DACEngine depends on SD-MMC_FATEngine... Another great object, which I would love to use in top-level code, without storing this resource twice on-chip.
As a result of this need, I tried integrating V2-WAV_DACEngine into top-level code.
As a result of repeated failure, I decided to isolate the problem by creating two, new, top-level files.
Normally, copying parts of methods, or entire methods, from various objects into top-level code would work fine, assuming the copied methods have access to the methods that they might call, and so on.
I'm not sure what I'm missing.
Thank you, in advance, for pointing me in the right direction.
Also, thank you, forum, for providing great coding examples. I have picked up numerous sweet techniques since my first visit to Parallax Discussion Forum.
pidzero
Greetings,
I've been using V2-WAV_DACEngine by Kwabena W. Agyeman, available on the Propeller Object Exchange. When I selected it, the object seemed to be the most appropriate one for me. Aside from small glitches every-so-often during playback of a large WAV file, it's perfect.
The V2-WAV_DACEngine depends on SD-MMC_FATEngine... Another great object, which I would love to use in top-level code, without storing this resource twice on-chip.
As a result of this need, I tried integrating V2-WAV_DACEngine into top-level code.
As a result of repeated failure, I decided to isolate the problem by creating two, new, top-level files.
intended-use.spin
|
+-- Simple_Serial.spin
|
+-- V2-WAV_DACEngine.spin
|
+-- SD-MMC_FATEngine.spin
desired-use.spin | +-- Simple_Serial.spin | +-- SD-MMC_FATEngine.spindesired-use.spin is the same as intended-use.spin with these exceptions:
* intended-use.spin sucessfully plays the audio file. desired-use.spin does not. Both files execute and indicate success to the LCD.
* desired-use.spin comments OBJ wav:"V2-WAV_DACEngine", changes wav. to {wav.}, and un-comments a copy of V2-WAV_DACEngine.spin, simply appended to the end of the file.
* desired-use.spin comments OBJ wav:"V2-WAV_DACEngine", changes wav. to {wav.}, and un-comments a copy of V2-WAV_DACEngine.spin, simply appended to the end of the file.
Normally, copying parts of methods, or entire methods, from various objects into top-level code would work fine, assuming the copied methods have access to the methods that they might call, and so on.
I'm not sure what I'm missing.
Thank you, in advance, for pointing me in the right direction.
Also, thank you, forum, for providing great coding examples. I have picked up numerous sweet techniques since my first visit to Parallax Discussion Forum.
pidzero

Comments
I noticed the OP has a fair amount of views, but no replies yet. (I know, "it hasn't even been a day yet, relax!")
I thought some information about what I'm trying to develop, bigger picture, would be helpful, and perhaps solicit valuable responses. (bump?)
So, I've been using the Prop1 for various not-highly-complex programs. What kind? LED light control, usually. One day, I decided an ambitious task of creating my own operating system.
Expressed another way:
1. Blink LED... check.
2. Develop mult-user, networking, operating system, in an interpreted language (Spin), that will interpret BASIC... (this really does sound ambitious, right? not to mention it's been done on various development platforms countless times before.)
Obviously, I had some level of confidence to even commit to it. Reasonably, it is possible to accomplish. Honorably, I cannot simply rebrand someone else's OS. Admittedly, I rely on other people's work to accomplish some tasks (trying to keep credits intact).
A little more info about my build: As previously stated, its an ambitious project (for me, anyway). It is my goal to have 4 working units with stable (even if immature) OS--by Christmas. 1 unit is for me, and 3 will be for close, less-tech-savy-than-me friends.
While your OS interface (aka command line) is vastly appealing to me, most of my intended users would be intimidated by it.
Obvious answer: make some menus, boot straight into a menu. Oh, the dilemma. When does code you got somewhere else become your own? Is it when you memorized it, and can produce it on-the-fly? Or is it when you press Ctrl-V and change a few things?
I digress. Regarding my testing of your OS, I don't have it successfully running yet, but I do have it boot-looping with debug(serial) output. I'm sure I'll get it running when I come back from a break from the computer. I did not copy any files to microSD yet; I'm sure that's it.
Henceforth, I will post my comments/questions/praises/etc about your OS on the appropriate discussion thread.
Also, I'll update this thread with any useful information I encounter about V2-WAV_DACEngine sharing SD-MMC_FATEngine with top-level spin.
pub xmount(do, clk, di, cs) return \sd.mount_explicit(do, clk, di, cs) pub open_file(p_str, cmd) '' If the file is opened successfully, 0 will be returned. return \sd.popen(p_str, cmd) pub close_file return \sd.pclose pub get_filesize return sd.get_filesize pub open_dir '' Sets up buffer for nextfile() return \sd.opendir pub next_file(p_str) '' Read next filename in root '' -- returns 0 if file, -1 if done return \sd.nextfile(p_str) pub rd_buf(ubuf, count) '' Returns the number of bytes successfully read, or a negative number return \sd.pread(ubuf, count) pub rd_line(p_str, n) | c, len '' Reads line from open text file '' -- terminated by LF or EOF '' -- p_str is address of string buffer '' -- n is maximum number of characters to read from line len := 0 ' index into string repeat n c := \sd.pgetc ' get a character if (c < 0) ' end of file if (len == 0) ' if nothing return -1 ' return empty else quit if (c <> $0A) ' if not LF char byte[p_str++] := c ' add to buffer len++ else ' if LF quit ' we're done byte[p_str] := 0 ' terminate end of line return len pub rd_byte '' Reads char from file. Returns negative number if error or end of file return \sd.pgetc pub wr_buf(ubuf, count) '' Returns the number of bytes successfully written '' -- or a negative number if there is an error. return \sd.pwrite(ubuf, count) pub wr_str(p_str) return \sd.pwrite(p_str, strsize(p_str)) pub wr_byte(b) return \sd.pputc(b)This may not be ideal for me. I'll illustrate. The pseudocode example below employs the technique you suggested:
{{top.spin}} OBJ lcd: "simple_serial" wav_play: "AWavePlayingObject.spin" DAT textFile byte "textfile.txt", 0 wavFile byte "wavfile.wav",0 errorString byte "An error has occurred!",0 doneString byte "All done with SD!", 0 PUB main ifnot \wav_play.initialize({initialization parameters}) lcd.str(@errorString) halt ifnot wav_play.fileExists(@textFile) wav_play.newFile(@textFile) wav_play.openFile(@textFile, "A"{append-mode}) wav_play.writeByte($41) wav_play.writeByte($42) wav_play.closeFile if wav_play.fileExists(@wavFile) if \wav_play.play(@wavFile) lcd.str(@errorString) halt repeat while wav_play.wavIsPlaying wav_play.openFile(@textFile, "A") wav_play.writeByte($43) wav_play.writeByte($44) wav_play.closeFile wav_play.end ' stop wav driver and SD access lcd.str(@doneString) halt PRI halt waitcnt(cnt+clkfreq) ' wait 1 second cogstop(0) ' stop the main cogHere, all SD operations--even ones that have nothing to do with playing WAVs--are called with wav_play.methodName.
While we have avoided object redundancy in this example by hooking, what happens when I add more objects depending on the same SD object:
OBJ
wav_rec : "AWaveRecordingObject.spin"
logger : "ADataLoggingObject.spin"
For simplicity, we will assume that simultaneous file-system access is not a requirement, but conserving EEPROM space is.