Spin Function Calls with multiple arguments
The fact that I can't find anyone who has asked this question suggests I'm barking up the wrong tree, but considering how new I am to the environment, I thought it worth asking (in case it's a common error).
I have created a function to handle writes to my microSD card (Activity Board, using the SD-MMC_FATEngine w/o RTC... though I need to add one). I had enountered some difficulties with corruption of my disk, so I decided that, for every write, I'd mount the disk system, create the file (in case of a card format/no file yet situation), open the file in append mode, then write several arguments to the log (temperature, humidity, and dewpoint). I only mention this in case it ends up giving a clue. I also discovered no good way to append data into a string variable (which is why I pass three arguments instead of one concatenated string).
So, here's what my function looks like. I'm pretty sure my error is in the function, since I use the same data items afterwards to send to an XBee Stick, and it shows up correctly there. The behavior I'm seeing is, no matter what order I arrange the parameters in, the last one in my parameter list ends up being copied over the other two. It's almost as if I'm only allowed one variable (which I know isn't true, since I have some two variable functions in my solution that work fine). Again, this is probably (hopefully) something dumb I'm overlooking... but in case it's a misunderstanding of Spin, I thought I'd ask (been looking at this function for an hour or so and I can't find the issue).
I have created a function to handle writes to my microSD card (Activity Board, using the SD-MMC_FATEngine w/o RTC... though I need to add one). I had enountered some difficulties with corruption of my disk, so I decided that, for every write, I'd mount the disk system, create the file (in case of a card format/no file yet situation), open the file in append mode, then write several arguments to the log (temperature, humidity, and dewpoint). I only mention this in case it ends up giving a clue. I also discovered no good way to append data into a string variable (which is why I pass three arguments instead of one concatenated string).
So, here's what my function looks like. I'm pretty sure my error is in the function, since I use the same data items afterwards to send to an XBee Stick, and it shows up correctly there. The behavior I'm seeing is, no matter what order I arrange the parameters in, the last one in my parameter list ends up being copied over the other two. It's almost as if I'm only allowed one variable (which I know isn't true, since I have some two variable functions in my solution that work fine). Again, this is probably (hopefully) something dumb I'm overlooking... but in case it's a misunderstanding of Spin, I thought I'd ask (been looking at this function for an hour or so and I can't find the issue).
PUB write_temp(fileID, percHum, fahrDP, fahrTemp) | errorString, errorNumber
fat.mountPartition(0) ' Mount the file system
errorString := \fat.newFile(fileID) ' Initial file creation (will give error if exists... we'll ignore this, since we know this is a valid use-case)
errorNumber := fat.partitionError ' Trap any errors (we only care if it's NOT file already exists)
if(errorNumber) ' Try to handle the "entry_already_exist" error.
if(errorNumber <> fat#Entry_Already_Exist)
return errorNumber
fat.openFile(fileID, "A") ' Open tempdata.txt for appending
fat.writeString(fahrTemp) ' Write data to microSD Card
fat.writeString(string("|"))
fat.writeString(percHum) ' Write data to microSD Card
fat.writeString(string("|"))
fat.writeString(fahrDP) ' Write data to microSD Card
fat.writeString(string(13, 10)) ' Write newline
fat.closeFile ' Close file
fat.unmountPartition

Comments
' Function to write temperature (in F), Humidity (in %), and Dewpoint (in F) to the log file if write_temp(string("temp_data.txt"),fp.FloatToFormat(percHum, 5, 1),fp.FloatToFormat(fahrDP, 5, 1),fp.FloatToFormat(fahrTemp, 5, 1)) XB.str(string("error writing to file"))Modified function (as I understood it):
PUB write_temp(fileID, percHum, fahrDP, fahrTemp) | errorString, errorNumber fat.mountPartition(0) ' Mount the file system errorString := \fat.newFile(fileID) ' Initial file creation (will give error if exists... we'll ignore this) errorNumber := fat.partitionError ' Trap any errors if(errorNumber) ' Try to handle the "entry_already_exist" error. if(errorNumber <> fat#Entry_Already_Exist) return errorNumber fat.openFile(fileID, "A") ' Open tempdata.txt for appending fat.writeString(fp.FloatToFormat(fahrTemp, 5, 1)) ' Write data to microSD Card fat.writeString(string("|")) fat.writeString(fp.FloatToFormat(percHum, 5, 1)) ' Write data to microSD Card fat.writeString(string("|")) fat.writeString(fp.FloatToFormat(fahrDP, 5, 1)) ' Write data to microSD Card fat.writeString(string(13, 10)) ' Write newline fat.closeFile ' Close tempdata.txt fat.unmountPartitionThe XBee tranmission block (has been working as expected since I first wrote it):
XB.start(XB_Rx, XB_Tx, 0, XB_Baud) ' Initialize comms for XBee {{.... the rest of the program, clipped out for clarity... }} XB.str(fp.FloatToFormat(fahrTemp, 5, 1)) ' Send the temperature string we just logged to our XBee terminal XB.str(string("|")) ' Send Pipe delimiter XB.str(fp.FloatToFormat(percHum, 5, 1)) ' Send the temperature string we just logged to our XBee terminal XB.str(string("|")) ' Send Pipe delimiter XB.str(fp.FloatToFormat(fahrDP, 5, 1)) ' Send the temperature string we just logged to our XBee terminal XB.Tx(CR)CON _clkmode = XTAL1|PLL16X _xinfreq = 5_000_000 OBJ dbg: "FullDuplexSerial" fp: "FloatString" PUB null dbg.start(31, 30, %0000, 115200) waitcnt(clkfreq*3 + cnt) dbg.tx(0) write_temp(string("temp.dat", 13), 93.4, 4.5, 2.3) PUB write_temp(fileID, percHum, fahrDP, fahrTemp) dbg.str(fileID) dbg.str(fp.FloatToFormat(fahrTemp, 5, 1)) dbg.str(string("|")) dbg.str(fp.FloatToFormat(percHum, 5, 1)) dbg.str(string("|")) dbg.str(fp.FloatToFormat(fahrDP, 5, 1)) dbg.str(string(13, 10)) DATwhich produces: So I'd say it's not the FloatToFormat at fault (any more).{ =============================================================================== } PUB buildDataString | locTime ''* builds the line to write to the µSD disk '' locTime := DateTime ' copy the global DateTime variable ByteFill(@FilData, 0, DATASIZE) ' clear the buffer Concatenate(@FilData, Tyme.jl_date_str(locTime, 0)) Concatenate(@FilData, string(",")) Concatenate(@FilData, Tyme.jl_time24_str(locTime, 0)) Concatenate(@FilData, string(",")) Concatenate(@FilData, FltStr.FloatToFormat(LocTemp, 5, 1)) ' upstairs temp Concatenate(@FilData, string(",")) Concatenate(@FilData, FltStr.FloatToFormat(LocHumid, 5, 1)) ' upstairs humidity Concatenate(@FilData, string(",")) Concatenate(@FilData, @DownTemp) ' downstairs temp Concatenate(@FilData, string(",")) Concatenate(@FilData, @OutTemp) ' outside temp Concatenate(@FilData, string(",")) Concatenate(@FilData, @OutHumid) ' outside humidity Concatenate(@FilData, string(13)) { =============================================================================== } PUB Concatenate(whereToPut, whereToGet) '' Concatenates a string onto the end of another. This method can corrupt memory. '' Returns a pointer to the new string. '' whereToPut - address of the string to concatenate a string to. '' whereToGet - address of where to get the string to concatenate. '' bytemove((whereToPut + strsize(whereToPut)), whereToGet, (strsize(whereToGet) + 1)) return whereToPutI believe I 'lifted' the Concatenate routine from another Spin library. Make sure that your strings are sized large enough or you'll definitely corrupt something!
I'll try again though, since its so much neater.
A combination of JLocke's suggestion and messing with exactly how I handle the line feeds between the XBee output and the file write finally did the trick. Btw, I believe that string routine you mentioned is either from the Strings v2.1 library (Brandon Nimon) or a very close approximation. I had previously tried to incorporate that library before, but since I was blissfully unaware of even the basics of how it was doing byte arrays, I was pretty dramatically unsuccessful. This second attempt was much better (thanks all). As far as the carriage returns, XBee wanted its constant CR ($D) transmitted seperately in its TX method, whereas the SD-MMC_Fate (SD card lib) wanted it sent seperately as string(13,10). Appending the carriage return to my byte array didn't seem to work for me (especially since the two libraries handled it so differently. So... final code (that's in the container logging humidity as I type this) we have (the sticky bits anyway):
PUB main | rawTemp, rawHumidity, celTemp, celDP, fahrTemp, fahrDP, percHum XB.start(XB_Rx, XB_Tx, 0, XB_Baud) ' Initialize comms for XBee fat.fatEngineStart( _dopin, _clkpin, _dipin, { ' Initialize the FAT engine } _cspin, _wppin, _cdpin, { } _rtcres1, _rtcres2, _rtcres3) f.start ' Start Floating Point Object sht.start(SHT_DATA, SHT_CLOCK) ' Start Sensirion Object sht.config(33,sht#off,sht#yes,sht#hires) 'Configure SHT-11 (High Res Mode) repeat ' Send temperature and humidity every 30 seconds ByteFill(@Buff, 0, 17) rawTemp := f.FFloat(sht.readTemperature) ' Read the raw temperature from the Sensirion rawHumidity := f.FFloat(sht.readHumidity) ' Read the raw humidity from the Sensirion celTemp := celsius(rawTemp) ' Calculate temperature in Celcius (required for Fahrenheit) fahrTemp := fahrenheit(celTemp) ' Calculate temperature in Fahrenheit (using temp in Celcius) percHum := humidity(celTemp, rawHumidity) ' Calculate humidity percentage celDP := dewpoint(celTemp, percHum) ' Calculate dewpoint in Celcius (required for Fahrenheit) fahrDP := fahrenheit(celDP) ' Calculate dewpoint in Fahrenheit (using dewpoint in Celcius) STR.Concatenate(@Buff, fp.FloatToFormat(fahrTemp, 5, 1)) STR.Concatenate(@Buff,string("|")) STR.Concatenate(@Buff, fp.FloatToFormat(percHum, 5, 1)) STR.Concatenate(@Buff,string("|")) STR.Concatenate(@Buff, fp.FloatToFormat(fahrDP, 5, 1)) XB.str(@Buff) XB.tx(CR) if write_temp(string("temp_data.txt")) XB.str(string("error writing to file")) Delay(10000)and
PUB write_temp(fileID) | errorString, errorNumber fat.mountPartition(0) ' Mount the file system errorString := \fat.newFile(fileID) ' Initial file creation (will give error if exists... we'll ignore this) errorNumber := fat.partitionError ' Trap any errors if(errorNumber) ' Try to handle the "entry_already_exist" error. if(errorNumber <> fat#Entry_Already_Exist) return errorNumber fat.openFile(fileID, "A") ' Open tempdata.txt for appending fat.writeData(@Buff,17) ' Write data to microSD Card fat.writeString(string(13, 10)) ' Write newline fat.closeFile ' Close tempdata.txt fat.unmountPartitionEither way, I took JLocke's advice and paid attention to my array dimension, and suddenly the concatenation worked
So, the original question was totally related to that. I'm still not 100% on the order of operations of function calls and variables, as I'm seeing very similar problems now trying to integrate a Real Time Clock library. The example code works fine, but when I try and integrate it into my app, it starts acting up. I clearly need to back up and start over again (from a basic code skills perspective). I'm code-cribbing successfully, but I've gone as far as I can with that (lazy) approach
This post is really just a thank you for the useful information from all. Its nice to have a knowledgeable community to help you get started.