Invalid conversion from 'const_FlashStringHelper*' to 'uint16_t'

You are right. I think I "improved" it without testing.

Fixed version below:

void mysscanf (char * line, const PROGMEM char * s, float & f)
  {
  char paramName [strlen_P (s) + 5];  // allow for trailing " %9s" and trailing 0x00
  char result [10];
  strcpy_P (paramName, s);
  strcat (paramName, " %9s");
  if (sscanf (line, paramName, result) > 0)
    f = atof (result);
  }  // end of mysscanf

void mysscanf (char * line, const PROGMEM char * s, int & i)
  {
  char paramName [strlen_P (s) + 5];    // allow for trailing " %7s" and trailing 0x00
  char result [8];
  strcpy_P (paramName, s);
  strcat (paramName, " %7s");
  if (sscanf (line, paramName, result) > 0)
    i = atoi (result);
  }  // end of mysscanf

float minPowerDownSoundTime;
int powerupDelay;

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  
  // some test lines
  char line1 [] = "minPowerDownSoundTime 42.34";
  char line2 [] = "powerupDelay 750";
  
  // scan for stuff 
  mysscanf (line1, PSTR ("minPowerDownSoundTime"), minPowerDownSoundTime); 
  mysscanf (line2, PSTR ("powerupDelay"), powerupDelay); 
    
  Serial.println (minPowerDownSoundTime);
  Serial.println (powerupDelay);
  }  // end of setup

void loop () { }

In regards to the far pointer issue... it's not as much of a concern as I thought. Apparently, it only comes into play when you have over 65,396 bytes of data in your program because data is shoved into the start of program memory just after the reset jump and vector table:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=1102883#1102883

So PROGMEM and F() will work fine on the ATMega1284 just as it does on the 328 for most peoplem, without any crazy workarounds.

Ugh.

I have removed the F() stuff for now because I need to get this up and running as quickly as possible and I should have plenty of space for my strings, but I still can't get the darn thing working and I have no way of doing serial debugging at this time.

The code is pretty simple, it should work, but the values don't seem to be being read. Specifically SWAP_LEDMODULES is not read. If that one value were read, I would know it.

Also, I've had the program halt and blink and LED if it gets into the swap() functions, and it appears to be gtting into the INT version of the swap() function, but never goes into the BYTE version, even though SWAP_LEDMODULES is a byte type. Any idea why that is?

Here's the code:

First, how the globals are setup:

  byte SWAP_LEDMODULES = 0; // 1 = Reverse order of powercell and bargraph LED modules to allow board to be installed in pack.
  
  byte ENABLE_POWERDOWN = 0; // Enable playing the powerdown sund every time the user flips off the Activate switch.
  
  byte BARGRAPH_STANDBY = 2; // Safety on
  byte BARGRAPH_IDLE = 1; // Ready to fire
  byte BARGRAPH_FIRE = 3; // Black button
  byte BARGRAPH_ALTFIRE = 4; // Red button

  byte POWERCELL_IDLE = 1; // Fill repeatedly.

    int powerupDelay = 750; // Number of milliseconds to wait before playing the powerup sound and continuing with pack animation.
    int humFadeTime = 300; // Number of seconds it takes for hum to fade out completely to conserve battery power.
    
    float maxSpeed = 10; // Number of seconds blast stream needs to be used for lights to move at maximum speed and for the pack to overheat.
    float currentSpeed = 0; // Roughly the number of seconds the fire button has been held for.  
    float normalSpeed = 0; // Range [0..1] (currentSpeed / maxSpeed); 
    
    float overheatWarning = 2; // Number of seconds warning you get before reaching max speed that you get a warning of impending overheat.  

    float minPowerDownSoundTime = 3;   // Number of seconds fire button needs to be held to get the shortest powerdown sound.
    float midPowerDownSoundTime = 5;
    float maxPowerDownSoundTime = 7;  // Number of seconds fire button needs to be held to get the longest powerdown sound. 
    
    // Note that sound played is actually based on how fast cyclotron is moving; these values assume that we're starting from 0.
    
    float heatup_Fire = 0; //0.5;    // Rate at which the pack speeds up when firing.  
    float heatup_AltFire = 1.0; // This could change based on the weapon.  For example, a shotgun-like weapon would only add this amount each time it fired.
    float heatup_Overload = maxSpeed / 3.0; // We want the overload to max out the pack's speed every time, and it lasts for three seconds, so maxSpeed / 3.0 gives us how much we need to add each second to make that happen.
    float heatup_Shotgun = maxSpeed / (8.0 * 0.625); // We want the shotgun to max out the pack's speed after X number of shots, and maxSpeed / (X * seconds of active heatup per shot) gives us how much speed to add each second to accomplish that. (Shotgun only heats up pack for first half second of each shot.) 
    float cooldown = 0.5; // 1.0 means the pack cools down at the same rate it heats up when firing.  2.0 would make it cooldown twice as fast.

Then the code to read the config file:

//  Scan line for keyword and parameter, and update parameter if found.
//  Return parameters found on success, 0 on failure.

  int scan(char* line, char* keyword, byte& i) {
    
    char format[strlen(keyword) + 5]; // Allow space for " %3s" + null.  strlen() returns the number of character up to, but not including null.
    char result[7]; 
    
    //halt(3); NEVER GET HERE
    
    strcpy(format, keyword); 
    strcat(format, " %3s"); 
    
    if (sscanf(line, format, result) == 1) {
      i = atoi(result);
      
      return 1;
    }  
    
  }
  
  int scan(char* line, char* keyword, int& i) {
    
    char format[strlen(keyword) + 5]; // Allow space for " %6s" + null.  strlen() returns the number of character up to, but not including null.
    char result[7]; 
    
    // halt(3); DO GET HERE
    
    strcpy(format, keyword); 
    strcat(format, " %6s"); 
    
    if (sscanf(line, format, result) == 1) {
      i = atoi(result);
      return 1;
    }  
    
  }
  
  int scan(char* line, char* keyword, float& f) {
    
    char format[strlen(keyword) + 5]; 
    char result[10]; 
    
    strcpy(format, keyword); 
    strcat(format, " %9s"); 
    
    if (sscanf(line, format, result) == 1) {
      f = atof(result);
      return 1;
    }
    
  }


void readConfigFile() {
    
  char line[256]; // Next line of text in file.
  //char fmt[32]; // Temporary variable for holding sscanf format strings read from flash.
  char fmt[32]; // Temporary variable for holding sscanf format strings read from flash.
  int n = 0; // Next parameter we want.
  int tmp; // Holds parameters that need to be modified before being put in another variable.
  
  if (!file.open(root, "PACK.CFG")) { Serial1.println(F("Failed to open PACK.CFG!")); halt(6); } // Error if file does not exist.

  // TEST:
    //file.fgets(line, sizeof(line));
    //if (*line == '#') halt(8);

  while (file.fgets(line, sizeof(line))) { // Read lines from the file until we hit the end. 
    
    if (*line == '#') continue; // Check first character on line.  If comment, skip to next line. (GOT HERE)
    
    if (scan(line, "powerupDelay", powerupDelay)) continue; 
    if (scan(line, "humFadeTime", humFadeTime)) continue; 
    
    if (scan(line, "maxSpeed", maxSpeed)) continue; 	
    if (scan(line, "overheatWarning", overheatWarning)) continue; 	
    
    if (scan(line, "minPowerDownSoundTime", minPowerDownSoundTime)) continue; 
    if (scan(line, "midPowerDownSoundTime", midPowerDownSoundTime)) continue; 
    if (scan(line, "maxPowerDownSoundTime", maxPowerDownSoundTime)) continue; 
      
    if (scan(line, "shotgunShotsOverheat", tmp)) { heatup_Shotgun = maxSpeed / (tmp * 0.625); continue; }
     
    if (scan(line, "SWAP_LEDMODULES", SWAP_LEDMODULES)) continue;
      
    if (scan(line, "ENABLE_POWERDOWN", ENABLE_POWERDOWN)) continue; 
      
    if (scan(line, "BARGRAPH_STANDBY", BARGRAPH_STANDBY)) continue; 
    if (scan(line, "BARGRAPH_IDLE", BARGRAPH_IDLE)) continue; 
    if (scan(line, "BARGRAPH_FIRE", BARGRAPH_FIRE)) continue;    
    if (scan(line, "BARGRAPH_ALTFIRE", BARGRAPH_ALTFIRE)) continue; 
    
    if (scan(line, "POWERCELL_IDLE", POWERCELL_IDLE)) continue;    
    	
  }
	
}

And here is the fgets function I added to the fat lib that comes with WaveHC:

Declaration:

int16_t fgets(char* str, int16_t num, char* delim = 0);  // Added by me, taken from SdFat lib.

Code:

/**

	This method was taken from the SDFat lib.  
	It does not work exactly like the standard fgets() function.  It can take a delimiter to allow you to stop reading when you hit a certain character.

 * Get a string from a file.
 *
 * fgets() reads bytes from a file into the array pointed to by \a str, until
 * \a num - 1 bytes are read, or a delimiter is read and transferred to \a str,
 * or end-of-file is encountered. The string is then terminated
 * with a null byte.
 *
 * fgets() deletes CR, '\\r', from the string.  This insures only a '\\n'
 * terminates the string for Windows text files which use CRLF for newline.
 *
 * \param[out] str Pointer to the array where the string is stored.
 * \param[in] num Maximum number of characters to be read
 * (including the final null byte). Usually the length
 * of the array \a str is used.
 * \param[in] delim Optional set of delimiters. The default is "\n".
 *
 * \return For success fgets() returns the length of the string in \a str.
 * If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
 **/

int16_t FatReader::fgets(char* str, int16_t num, char* delim) {
  char ch;
  int16_t n = 0;
  int16_t r = -1;
  while ((n + 1) < num && (r = read(&ch, 1)) == 1) {
    // delete CR
    if (ch == '\r') continue;
    str[n++] = ch;
    if (!delim) {
      if (ch == '\n') break;
    } else {
      if (strchr(delim, ch)) break;
    }
  }
  if (r < 0) {
    // read error
    return -1;
  }
  str[n] = '\0';
  return n;
}

Pulling my hair out over this. It's probably something really stupidly simple like I didn't pass a pointer right to a function.

Here is the actual file being read:

# This file contains parameters you can adjust to change the behavior of the proton pack kit.

powerupDelay 750 		# Time to wait before playing the powerup sound and continuing with pack animation. Allows amp time to warm up. (milliseconds)
humFadeTime 300			# Time it takes for hum to fade out completely to conserve battery power. Hum will return to full volume again as soon as any other sound is played. (seconds)  

maxSpeed 10			# Time blast stream needs to be fired continuously to get lights to move at maximum speed and for the pack to overheat. (seconds)
overheatWarning 2 		# Time before reaching max speed that you get warning beeps for impending overheat. (seconds)

minPowerDownSoundTime 3 	# How long fire button needs to be held to get the short powerdown sound. (seconds)
midPowerDownSoundTime 5	# How long fire button needs to be held to get the medium powerdown sound. (seconds)
maxPowerDownSoundTime 7 	# How long fire button needs to be held to get the long powerdown sound. (seconds)

shotgunShotsOverheat 8	# Number of times shotgun must be fired to cause pack to overheat.

SWAP_LEDMODULES 0 		# 0 = Default LED module order, 1 = Reverse order of powercell and bargraph LED modules to allow Mighty to be installed in pack.

ENABLE_POWERDOWN 0		# 0 = No powerdown sound on deactivate. 1 = Powerdown sound when deactivate. (pwrdown.wav)

BARGRAPH_STANDBY 1 		# Safety ON animaton
BARGRAPH_IDLE 2 		# Ready to fire
BARGRAPH_FIRE 3 		# Black button - Capture stream
BARGRAPH_ALTFIRE 4 		# Red button - Blast stream

POWERCELL_IDLE 1		# Idling animation

# Bargraph animations:
#
# 0 - Off
# 1 - Fill and empty (Default safety)
# 2 - Random fill and empty (Default ready to fire)
# 3 - Ends to center to ends (Default capture stream)
# 4 - Ends to center (Default blast stream)
# 5 - Music mode (Displays current song)
# 6 - Reset (Resets shotgun animation)
# 7 - Ends to center (Default shotgun animation - One shot until reset)
# 8 - Do nothing (For future use)
# 9 - Solid
# 10 - Vent drain (Used when venting - drains quickly)
# 11 - Overheat drain (Used after overheat - drains slowly)
#
# For full movie accuracy, set STANDBY to 9, and IDLE, FIRE, and ALTFIRE to 1.  
# To swap the random fill and normal fill animations, set STANDBY to 2, and IDLE to 1.

# Powercell animations:
# 
# 1 - Fill normally, speeding up as pack heats up.
# 2 - Fill halfway, then as pack heats up speed up and increase leds that light.

Have you considered using sscanf_P, and forgetting about floating-point altogether?

I need floating point for my end users. These config files are for them. And they aren't programmers and would not like dealing with weird values like 4095 for specifying led brightness.

Well, there's a little good news... while the PACK.CFG file reader is not functioning properly, my LED.CFG file is being read properly now. Here is the code for that:

// LED config scan function. 
// index, scale, speed

  int scanLED(char* line, int& i, float& f1, float& f2) {
    
    char result_i[7]; 
    char result_f1[10]; 
    char result_f2[10];
    
    if (sscanf(line, " %6s %9s %9s", result_i, result_f1, result_f2) == 3) {
      i = atoi(result_i);
      f1 = atof(result_f1);
      f2 = atof(result_f2);
      return 3;
    }
    
  }

  
void readLEDConfig() {
    
  char line[256]; // Next line of text in file.
  int index = 1, lastIndex;
  float scale = 1.0, lastScale;
  float speed = -1.0, lastSpeed;
  
  if (!file.open(root, "LED.CFG")) { Serial1.println(F("Failed to open LED.CFG!")); halt(7); } // Error if file does not exist.
  
  while (file.fgets(line, sizeof(line))) { // Read lines from the file until we hit the end.
    
    if (line[0] == '#') continue; // Check first character on line.  If comment, skip to next line.
    
    // Store last set of values read from the file before reading new ones:
    
      lastIndex = index;
      lastScale = scale; 
      lastSpeed = speed; 
    
    if (scanLED(line, index, scale, speed) == 3) { // Scan line.  If all parameters accounted for, store them, then execute code below.
      
      // Loop through all LEDs up to this point and fill them with previously read values.  Do not update the LED we just read parameters for yet.
      
        for (int i = lastIndex; i < index; i++) { // Loop through and set all LEDs up to, but not including, the one we just read from the file. 
          led::setscale(i, lastScale); 
          led::speed[i-1] = lastSpeed; // LEDs are 1-indexed but LED arrays are 0-indexed so we subtract 1 here.  
        }        
      
    } else { 
      
      // Line may be blank, or contain a few whiespace characters.  Or it may be improperly formatted.
      
      //Serial1.println(F("Improperly formatted line in LED.CFG!")); 
      //halt(7); 
      
    }
  
  }

  for (int i = lastIndex; i <= leds; i++) { // Loop through remaining LEDs and set their values, starting from last one read. 
    led::setscale(i, scale); 
    led::speed[i-1] = speed; 
  } 

  // No need to bother closing file if we're not writing to it. 
    
}

This tells me fgets is working. So the issue must be something else.

I notice that your scan functions don't execute a return statement -- something like "return 0;" -- unless they actually find the requested identifier.

According to the standard, what your scan function returns to the caller is undefined without an explicit return statement. (...so it might quite possibly be "not zero", which would cause your parsing loop to continue early. Or it might happen to be zero; then you've gotten lucky.)

Ah. That's good to know. I'll try that. I just assumed it returned 0. I'm not sure how that hasn't bitten me before now.

Michael:

That appears to have been it. God, I would have been looking for that for hours. Thanks!

And they aren't programmers and would not like dealing with weird values like 4095 for specifying led brightness

I am a programmer, and would much rather work with values specified in multiples of, say, tenths or hundredths of a percent.

One more question...

Why am I getting a compiler error here?

Declaration in class:

bool exists(char* name);

Function:

bool FatReader::exists(char* name) {
	FatReader tmp;
	return tmp.open(this, name);
}

Function called:

uint8_t FatReader::open(FatReader &dir, char *name) {

The compiler is telling me "no matching function for call to 'FatReader::open(FatReader* const, char*&)'"

Why is there an & on the end there?

I pass a pointer to an array of chars to the function. 'name' is a pointer to type char. I then pass 'name' along to another function which also takes a pointer to an array of type char as input. Where's the problem here?

I don't think I'm supposed to deference the pointer... then I'd be passing the character at the location the pointer points to instead of the address in the pointer. Right?

Can you post enough code for me to reproduce that please? Not just a few lines.

It's a ton of code, like a whole fat reader lib. I gotta get this done tonight and by the time I worked up a sample the forums would be down for hours. I'll just work around it.

Anyway, I did a quick test and found that what it's really complaining about is the use of "this" there. For some reason it doesn't want to pass "this" to "uint8_t FatReader::open(FatReader &dir, char *name)". If I pass it the tmp variable instead which is of type FatReader then it works fine. Going by the error message it seems to want a const in there for some reason.

this is a pointer, FatReader &dir is a reference.

*this probably would have worked.

I think I understand what's going on now.

The 'open' method takes it's directory input by reference. Which would allow it to modify the variable passed to it. But 'this' cannot be modified. So the compiler complains.

Hm...

It seems like using a reference there is not the correct way of going about things then? I guess I'll look up how one would usually pass an object to a function. I didn't write the WaveHC fat lib, and the SDFat lib works a bit differently and has the open function declared differently which allows it to work without the *.

This is how that lib handles it:

bool SdBaseFile::open(SdBaseFile* dirFile, const char* path, uint8_t oflag)

I just tried your suggestion to dereference 'this' before passing it to the open function (I get what's going on now), and sure enough, it works. I guess that's solved. Thanks. :slight_smile:

scswift:
The 'open' method takes it's directory input by reference. Which would allow it to modify the variable passed to it. But 'this' cannot be modified. So the compiler complains.

Well, one is the right type and one isn't. It is the wrong type, regardless of whether it can be modified or not.