These are chat archives for esp8266/Arduino

14th
Jul 2016
Holger Lembke
@holgerlembke
Jul 14 2016 09:51
if I take the esp8266ssdp/ssdp example, shall my esp be visible in the devices list without installing something on windows?
Me No Dev
@me-no-dev
Jul 14 2016 11:35
yup. on windows where you see your webcam, joystick, printers and so on
Holger Lembke
@holgerlembke
Jul 14 2016 12:15
so it does not work with my windows
i see a lot of stuff, but not a hue
Holger Lembke
@holgerlembke
Jul 14 2016 13:43
ok, sspd does a "REJECT: upnp:rootdevice"
Holger Lembke
@holgerlembke
Jul 14 2016 13:59
ok2, adding SSDP.setDeviceType("upnp:rootdevice"); and it starts working....
andig
@andig
Jul 14 2016 15:55
@me-no-dev thanks for the pointer to ESPAsyncTCP.cpp for the static _s callback methods. How is the (arg) populated by the lwip functions- is that compiler magic?
andig
@andig
Jul 14 2016 18:34
Still this doesn't compile- arrrgh:
public:
  InterruptHandler(S0Plugin* plugin, int pin, int mode) : _plugin(plugin), _pin(pin) {
    attachInterrupt(pin, &_s_interruptHandler, mode);
  }

  static void _s_interruptHandler(void* arg) {
    // reinterpret_cast<InterruptHandler*>(arg)->_plugin->handleInterrupt();
  }
};
Me No Dev
@me-no-dev
Jul 14 2016 18:35
is _plugin public or protected?
what is the compilation error?
andig
@andig
Jul 14 2016 18:53
This message was deleted
This message was deleted

multiple problems:

plugins/S0Plugin.cpp:16:56: error: invalid conversion from 'void (*)(void*)' to 'void (*)()' [-fpermissive

]

that is _s function signature. its fine without the void* arg which I need for this obviously
actually, thats the only problem.
Me No Dev
@me-no-dev
Jul 14 2016 18:59
and what is on that line?
how do you attach _s_interruptHandler
andig
@andig
Jul 14 2016 18:59

on the attachInterrupt, followed by

.pioenvs/base/FrameworkArduino/Arduino.h:213:6: error:   initializing argument 2 of 'void attachInterrupt(

uint8_t, void (*)(), int)' [-fpermissive]

Me No Dev
@me-no-dev
Jul 14 2016 19:00
oh...
you can not use attachInterrupt here
forget about that one
andig
@andig
Jul 14 2016 19:00
heres the full platformio message:
plugins/S0Plugin.cpp: In constructor 'InterruptHandler::InterruptHandler(S0Plugin*, int, int)':
plugins/S0Plugin.cpp:16:56: error: invalid conversion from 'void (*)(void*)' to 'void (*)()' [-fpermissive
]
attachInterrupt(pin, &_s_interruptHandler, mode);
^
In file included from plugins/Plugin.h:4:0,
from plugins/S0Plugin.h:4,

from plugins/S0Plugin.cpp:1:
.pioenvs/base/FrameworkArduino/Arduino.h:213:6: error:   initializing argument 2 of 'void attachInterrupt(
uint8_t, void (*)(), int)' [-fpermissive]
void attachInterrupt(uint8_t pin, void (*)(void), int mode);
^
scons: *** [.pioenvs/base/src/plugins/S0Plugin.o] Error 1
Me No Dev
@me-no-dev
Jul 14 2016 19:00
you need to roll out your own implementation (copy/paste most of it and add the arg)
andig
@andig
Jul 14 2016 19:01
I see- I need to make it a member function?
I still don't get why that trick works in asynctcp then?
Me No Dev
@me-no-dev
Jul 14 2016 19:03
attachInterrupt is a basic implementation for more regular uses and is in C
you need to copy it's code and replace where it calls the handlers to actually call your class
ETS_GPIO_INTR_ATTACH(_s_interruptHandler, this);
that is where you hook into
then is _s_interruptHandler you what the regular ISR does to clear interrupts and so on
andig
@andig
Jul 14 2016 19:06
ok, the "regular" stuff is in interrupt_handler which core has an array of
seems I need to circumvent this array- looking for the attaching part right now
yikes- all interrupts are sharing the same single handler
Me No Dev
@me-no-dev
Jul 14 2016 19:07
yup
andig
@andig
Jul 14 2016 19:08
I dont think that can be done in user land as I don't have access to the interrupt_handlers array. So I'd void other code running in parallel that uses interrupts?
Me No Dev
@me-no-dev
Jul 14 2016 19:09
bind maybe?
Michael Miller
@Makuna
Jul 14 2016 19:11
@andig You have an extra indirection in this call (removed the &)
attachInterrupt(pin, _s_interruptHandler, mode);
andig
@andig
Jul 14 2016 19:12
@Makuna same error
this is the handler:
static uint32_t interrupt_reg = 0;

void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
  uint32_t status = GPIE;
  GPIEC = status;//clear them interrupts
  uint32_t levels = GPI;
  if(status == 0 || interrupt_reg == 0) return;
  ETS_GPIO_INTR_DISABLE();
  int i = 0;
  uint32_t changedbits = status & interrupt_reg;
  while(changedbits){
    while(!(changedbits & (1 << i))) i++;
    changedbits &= ~(1 << i);
    interrupt_handler_t *handler = &interrupt_handlers[i];
    if (handler->fn && 
        (handler->mode == CHANGE || 
         (handler->mode & 1) == !!(levels & (1 << i)))) {
      // to make ISR compatible to Arduino AVR model where interrupts are disabled
      // we disable them before we call the client ISR
      uint32_t savedPS = xt_rsil(15); // stop other interrupts 
      handler->fn();
      xt_wsr_ps(savedPS);
    }
  }
  ETS_GPIO_INTR_ENABLE();
}

mmhm. why can't I inline create something that looks like an

 typedef struct {
  uint8_t mode;
  void (*fn)(void);
} interrupt_handler_t;

which holds a reference to this and pass that to regular attachInterrupt?

`

andig
@andig
Jul 14 2016 19:17
something like [this](void){ this.handle_the_interrupt(); }?
unfortunately that breaks as soon as this is captured:
plugins/S0Plugin.cpp: In constructor 'InterruptHandler::InterruptHandler(S0Plugin*, int, int)':

plugins/S0Plugin.cpp:18:16: error: cannot convert 'InterruptHandler::InterruptHandler(S0Plugin*, int, int)
::__lambda0' to 'void (*)()' for argument '2' to 'void attachInterrupt(uint8_t, void (*)(), int)'
}, mode);
^
Ivan Grokhotkov
@igrr
Jul 14 2016 19:52
This breaks because you can't pass a function object in place of function pointer.
andig
@andig
Jul 14 2016 19:54
yes, understood. but why does the static method fail? imho thats similar to espasynctcp with c code calling c++ handler and "inventing" the this arg?
Michael Miller
@Makuna
Jul 14 2016 19:54
attachInterrupt(pin, classname::_s_interruptHandler, mode);
andig
@andig
Jul 14 2016 19:55
I mean this:
tcp_accept(_pcb, _s_accept);

int8_t AsyncServer::_s_accept(void *arg, tcp_pcb* pcb, int8_t err){
  return reinterpret_cast<AsyncServer*>(arg)->_accept(pcb, err);
}
Me No Dev
@me-no-dev
Jul 14 2016 19:55
because the callback does not take an void * arg
andig
@andig
Jul 14 2016 19:55
@Makuna also tried that :O
but it doesnt for tcp_accept either???
Me No Dev
@me-no-dev
Jul 14 2016 19:55
it does for tcp_accept
Ivan Grokhotkov
@igrr
Jul 14 2016 19:55
well you can use static member function, but this function needs to be void(void)
Me No Dev
@me-no-dev
Jul 14 2016 19:55
it does not for attachInterrupt
Ivan Grokhotkov
@igrr
Jul 14 2016 19:56
i.e. static void handleFoo(void) {...}
and then you attachInterrupt(pin, &MyClass::handleFoo, RISING)
that'll work
andig
@andig
Jul 14 2016 19:57
yes, understood. I'm failing to grasp why that works for the asyncserver above then?
too stupid tonight :O
Ivan Grokhotkov
@igrr
Jul 14 2016 19:57
that's exactly what asyncserver is doing
so no surprise it works :)
andig
@andig
Jul 14 2016 19:58
sorry, I'm talking rubbish. tcp_accept works with callback that have arg, attachinterrupt doesn't.
where is the tcp_accept function type declared that allows that?
Me No Dev
@me-no-dev
Jul 14 2016 19:59
so you are asking about attachInterruptbut then talking about tcp stuff?
it's not at all connected :)
andig
@andig
Jul 14 2016 20:00
yes. yes and yes.
Me No Dev
@me-no-dev
Jul 14 2016 20:00
we did not implement arg in the callback
it has implementation deeper in the code
that is why I suggested you to implement it your own way
andig
@andig
Jul 14 2016 20:02
I thought the tcp_accept callback has pcb as arg, but void *arg as first arg works, too. If that was the case for attachInterrupt I'd be saved. All I'm saying is that I couldn't figure out why and where thats done for tcp_accept.
Ivan Grokhotkov
@igrr
Jul 14 2016 20:02
it's pretty simple. attachInterrupt expects to see a void(void) function. tcp_accept expects to see a void(void*, tcp_pcb*, int8_t) function.
Me No Dev
@me-no-dev
Jul 14 2016 20:02
on top of that attachInterrupt is weak so you can overwrite it
andig
@andig
Jul 14 2016 20:03
there we go, thanks @igrr as for overriding attachInterrupt I'd need access to the interrupt_handlers array. Can I get that via extern C {} ?
Ivan Grokhotkov
@igrr
Jul 14 2016 20:04
no it's static IIRC
so just declare your own
you will need to store a void* arg somewhere anyway, so you will need a different/larger array
Ivan Grokhotkov
@igrr
Jul 14 2016 20:05
btw, esp8266/Arduino#1925
Me No Dev
@me-no-dev
Jul 14 2016 20:06
then that logic needs to move out of C, does it not?
Ivan Grokhotkov
@igrr
Jul 14 2016 20:07
yeah, rename .c -> .cpp, add a bunch of extern "C", sorta like that
Me No Dev
@me-no-dev
Jul 14 2016 20:07
:D
Ivan Grokhotkov
@igrr
Jul 14 2016 20:07
change function pointer array to an std::function<void(void)> array
andig
@andig
Jul 14 2016 20:08
there's my beloved bind() :smile:
Ivan Grokhotkov
@igrr
Jul 14 2016 20:11
there is a slight issue with C code which might call attachInterrupt though. for this i suggest to have two attachInterrupt declarations — legacy one, declared as extern "C" for ifdef __cplusplus and also declared for ifndef __cplusplus, and a new one, declared without extern "C", and only for ifdef __cplusplus.
andig
@andig
Jul 14 2016 20:11
@igrr can I ask one more teaching question? How does the tcp_accept callback populate the void* pointer, i.e. how does it know which class instance it was initialized from?
Ivan Grokhotkov
@igrr
Jul 14 2016 20:12
through tcp_arg
you call tcp_arg to set a void* argument to be used for all callbacks associated with a given pcb
andig
@andig
Jul 14 2016 20:12
oh, got it. over and out, learned a lot, thanks!
could add an attachinterrupt_arg ;)
Ivan Grokhotkov
@igrr
Jul 14 2016 20:16
about to board a 13 hour flight. gotta find a nice long task to work on...
Holger Lembke
@holgerlembke
Jul 14 2016 20:18
pfffff. 13 hours. all that noise. cancelling headphones?
andig
@andig
Jul 14 2016 20:20
hopefully business....