typedef visible for variables but not for function parameters

Hello Arduino-Experts,

I want to use IRMP to communicate with IR remotes and the respective IR controlled devices. I am currently using the IRMPforArduino library. IRMP decodes IR data frames and stores them in a varaible of type IRMP_DATA. I can use this type as a variable just fine. However, when I try to use it as a method parameter, the IDE complains about:

arduino_irmp_example-mod.ino:23: error: 'IRMP_DATA' was not declared in this scope

IRMPforArduino comes with an example "arduino_irmp_example", which compiles just fine. In this example sketch, IRMP_DATA is used once as a global variable to store received frames.

To show the error, I modified the example sketch. The original version prints the contents of an IR frame to the serial port inside the loop() function. I factored this out into a function printFrame(IRMP_DATA frame) (making the parameter a pointer or a reference doesn't change anything). See the complete modified code here (also attached to this post for your convenience):

/* This is a simple example for using the IRMP library
 * original home of IRMP is:  http://www.mikrocontroller.net/articles/IRMP
 * arduino port of IRMP home: https://gitorious.org/arduino-addons/irmp-arduino
 *
 * (C) 2012 Stefan Seyfried
 * (C) 2014 Falko Thomale
 *
 * This program is free software. It comes without any warranty, to
 * the extent permitted by applicable law. You can redistribute it
 * and/or modify it under the terms of the Do What The Fuck You Want
 * To Public License, Version 2, as published by Sam Hocevar. See
 * http://sam.zoy.org/wtfpl/COPYING for more details. 
 */

/* use TimerOne http://arduino.cc/playground/Code/Timer1 for interrupts */
#include <TimerOne.h>
/* first include Arduino.h, the IDE includes it after irmp*.h ... */
#include "Arduino.h"
/* ... and then chokes on uintX_t ... */

extern "C" {
#include <irmp.h>
#include <irsnd.h>
}

/* undefine this if you don't want blinking LED for diagnosis */
#define LED_PIN 4
#define SER_BAUD 9600

/* F_INTERRUPTS is the interrupt frequency defined in irmpconfig.h */
#define US (1000000 / F_INTERRUPTS)
void setup()
{
  Serial.begin(SER_BAUD);
  /* greeting string and debugging ouput */
  Serial.println("IRMP test sketch");
  Serial.print("US: ");
  Serial.println(US);
#ifdef LED_PIN
  pinMode(LED_PIN, OUTPUT);
#endif
  //irmp_init();
  irsnd_init();
  //sei();
  led(HIGH);
  delay(20); /* make sure the greeting string is out before starting */
  led(LOW);
  Timer1.initialize(US);
  Timer1.attachInterrupt(timerinterrupt);
}

void printFrame(IRMP_DATA frame) {
    led(HIGH);
    Serial.print("P:");
    Serial.print(frame.protocol, HEX);
    Serial.print(" A:");
    Serial.print(frame.address, HEX);
    Serial.print(" C:");
    Serial.print(frame.command, HEX);
    Serial.print(" ");
    Serial.print(frame.flags, HEX);
    Serial.println("");
    /* Serial.print is asynchronous, so the LED is only flashing very lightly */
    led(LOW);
}


IRMP_DATA irmp_data;
int incomingByte = 0;   // for incoming serial data
void loop()
{
  if (irmp_get_data(&irmp_data))
  {
    printFrame(irmp_data);

    irmp_data.flags = 0;    // reset flags!
    int result = irsnd_send_data(&irmp_data, TRUE);
    if (result != 1)
      Serial.println("ERROR");
  }

  if (Serial.available() == 18 && readAndCheck('P') && readAndCheck(':')) {
    // read the protocol
    irmp_data.protocol = readHex() * 16 + readHex();

    if (readAndCheck(' ') && readAndCheck('A') && readAndCheck(':')) {
      // read the address
      irmp_data.address = ((readHex() * 16 + readHex()) * 16 + readHex()) * 16 + readHex();

      if (readAndCheck(' ') && readAndCheck('C') && readAndCheck(':')) {
        // read the address
        irmp_data.command = ((readHex() * 16 + readHex()) * 16 + readHex()) * 16 + readHex();

        // send ir data
        irmp_data.flags = 0;
        int result = irsnd_send_data(&irmp_data, TRUE);
        if (result)
        {
          Serial.println("Send IR data: ");
          Serial.print("P:");
          Serial.print(irmp_data.protocol, HEX);
          Serial.print(" A:");
          Serial.print(irmp_data.address, HEX);
          Serial.print(" C:");
          Serial.print(irmp_data.command, HEX);
          Serial.println("");
        }
      }
    }
  }
}

/* helper function: attachInterrupt wants void(), but irmp_ISR is uint8_t() */
void timerinterrupt()
{
  if (! irsnd_ISR())          // call irsnd ISR
  {                           // if not busy...
    irmp_ISR();               // call irmp ISR
  }
}

static inline void led(int state)
{
#ifdef LED_PIN
  digitalWrite(LED_PIN, state);
#endif
}

static inline int readAndCheck(int c)
{
  return c == Serial.read();
}

static inline int readHex()
{
  int c = Serial.read();
  if (c >= '0' && c <= '9')
  {
    return c - '0';
  }
  else if (c >= 'a' && c <= 'f')
  {
    return c + 10 - 'a';
  }
  else if (c >= 'A' && c <= 'F')
  {
    return c + 10 - 'A';
  }

  return -1;
}

When I hit compile in the Arduino IDE, I get the following error:

Arduino: 1.0.6 (Mac OS X), Board: "Arduino Uno"
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=106 -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/variants/standard -I/Users/deltaphi/Documents/Arduino/Sketchbook/libraries/Timer1 -I/Users/deltaphi/Documents/Arduino/Sketchbook/libraries/IRMPforArduino /var/folders/tv/1q4yyzvj7731140vvy2qzhgm0000gn/T/build7877868992204864271.tmp/arduino_irmp_example-mod.cpp -o /var/folders/tv/1q4yyzvj7731140vvy2qzhgm0000gn/T/build7877868992204864271.tmp/arduino_irmp_example-mod.cpp.o 
arduino_irmp_example-mod.ino:23: error: variable or field 'printFrame' declared void
arduino_irmp_example-mod.ino:23: error: 'IRMP_DATA' was not declared in this scope

Line 23 is "#include <irsnd.h>" rather than the definition of printFrame().

What gives? Why is the type known in one place but not in another? Have I lost all of my programming knowledge over night or is there a more rational explanation?

Regards,
deltaphi

arduino_irmp_example-mod.ino (3.86 KB)

What gives? Why is the type known in one place but not in another? Have I lost all of my programming knowledge over night or is there a more rational explanation?

Haha you can calm down, there is an explanation (down the bottom is an easy fix for your functions),
http://arduino.land/FAQ/content/2/13/en/my-class_reference-won_t-work-in-the-sketch.html

Why is the #include for irmp.h wrapped in an extern "C" block?

The IDE may not be generating a function prototype for the printFrame() function. You may need to define your own.

PaulS:
The IDE may not be generating a function prototype for the printFrame() function. You may need to define your own.

The problem is the IDE is generating a prototype, but it is placed above the include. The link I posted shows how to prevent a prototype from being generated. Your method of adding one ( below the includes ) is also a solution.

Hello,

pYro_65:

Why is the type known in one place but not in another?

Haha you can calm down, there is an explanation (down the bottom is an easy fix for your functions),
http://arduino.land/FAQ/content/2/13/en/my-class_reference-won_t-work-in-the-sketch.html

that link does not work. I only see "Access Denied" ("Zugriff verweigert"). The entire FAQ section of that page appears to be void of actual content.

PaulS:
Why is the #include for irmp.h wrapped in an extern "C" block?

I honestly don't know. All the examples do it this way. When you remove the extern "C", you get the following:

arduino_irmp_example-mod.cpp.o: In function `timerinterrupt()':
/Applications/arduino_irmp_example-mod.ino:118: undefined reference to `irsnd_ISR()'
/Applications/arduino_irmp_example-mod.ino:120: undefined reference to `irmp_ISR()'
arduino_irmp_example-mod.cpp.o: In function `loop':
/Applications/arduino_irmp_example-mod.ino:74: undefined reference to `irmp_get_data(IRMP_DATA*)'
/Applications/arduino_irmp_example-mod.ino:79: undefined reference to `irsnd_send_data(IRMP_DATA*, unsigned char)'
/Applications/arduino_irmp_example-mod.ino:98: undefined reference to `irsnd_send_data(IRMP_DATA*, unsigned char)'
arduino_irmp_example-mod.cpp.o: In function `setup':
/Applications/arduino_irmp_example-mod.ino:45: undefined reference to `irsnd_init()'

Everything is compiled through the Arduino IDE, so the usual reason of "accessing stuff compiled using a C compiler" shouldn't hold.

PaulS:
The IDE may not be generating a function prototype for the printFrame() function. You may need to define your own.

Thank you, that solved my initial problem. The code is compiling now.

Combined with pYro_65's subsequent comment and to clarify on this: Am I correct in assuming that this is working around an issue caused by the IDE rather than an actual C++ problem? Whenever I define a function in the .ino file, Arduino automatically adds a prototype definition at the start of the resulting file for compilation, unless there is a prototype definition in the file itself. In my case, the prototype definition is not required, as I am defining the function before (in terms of source lines) its first use.
So, if Arduino wouldn't insist on adding prototypes, this issue would not have appeared. Correct?

Regards,
deltaphi

that link does not work. I only see "Access Denied" ("Zugriff verweigert"). The entire FAQ section of that page appears to be void of actual content.

The link works for me.

Am I correct in assuming that this is working around an issue caused by the IDE rather than an actual C++ problem? Whenever I define a function in the .ino file, Arduino automatically adds a prototype definition at the start of the resulting file for compilation, unless there is a prototype definition in the file itself. In my case, the prototype definition is not required, as I am defining the function before (in terms of source lines) its first use.
So, if Arduino wouldn't insist on adding prototypes, this issue would not have appeared. Correct?

There is only one way to know...