As the title says... Chat on...

User avatar
By cal
#16015
dnc40085 wrote:As for just fixing it or understanding the issue, I'll take option B as I've been trying to figure it out on my own with no avail.


OK, Lesson 1 ;-)

Take the relevant c function from wifi.c and document it here with your guesses of what the lines mean.
The function is pretty short so it should be doable.
Don't take it too serious if you are wrong but don't take research to lightly, too.
Don't dig to deep into the inner workings of the methods/macros,.
Take them literally at the beginning and dig deeper when wanted or needed.
Reading a little about lua as a stack oriented language and lua garbage collection may help.
If it does not make much sense it's OK, hopefully it gets clearer later.
User avatar
By dnc40085
#16055 Alright, here goes...

Code: Select allstatic int wifi_station_listap( lua_State* L )
{
  if(wifi_get_opmode() == SOFTAP_MODE)  //if esp8266 operating mode is  SOFTAP then...
  {
    return luaL_error( L, "Can't list ap in SOFTAP mode" ); // return error
  }
  gL = L; //copies pointer "L" to a global variable "gL" so it can be used in wifi_scan_done later

  if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION){ // if index 1 of "L" is a function then...
    lua_pushvalue(L, 1);  // copy argument (func) to the top of stack

    if(wifi_scan_succeed != LUA_NOREF)// if variable(wifi_scan_succeed) is NOT equal to constant (LUA_NOREF(-2)) then...
      luaL_unref(L, LUA_REGISTRYINDEX, wifi_scan_succeed); //release previous reference and corresponding value???

    wifi_scan_succeed = luaL_ref(L, LUA_REGISTRYINDEX); //create reference(lua pointer) to lua value and store the ID for the reference in the variable "wifi_scan_succeed"
    wifi_station_scan(NULL,wifi_scan_done); //call station scan function from SDK
  } else { // if index 1 of "L" is NOT a function then...
    if(wifi_scan_succeed != LUA_NOREF) // if variable(wifi_scan_succeed) is NOT equal to constant (LUA_NOREF(-2)) then...
      luaL_unref(L, LUA_REGISTRYINDEX, wifi_scan_succeed); //release previous reference and corresponding value???
    wifi_scan_succeed = LUA_NOREF; //set variable "wifi_scan_succeed" to "LUA_NOREF(-2)" since the value corresponds to a non-existent reference 
  }
}


Code: Select allstatic void wifi_scan_done(void *arg, STATUS status)
{
  uint8 ssid[33];  // Initialize variable "ssid"
  char temp[128]; // Initialize variable "temp"
  if(wifi_scan_succeed == LUA_NOREF) //if variable "wifi_scan_succeed" contains no reference(lua pointer) then...
    return; // since there is no reference ID, return
  if(arg == NULL) //if variable "arg" is NULL then...
    return; //there is nothing to process so return
 
  lua_rawgeti(gL, LUA_REGISTRYINDEX, wifi_scan_succeed); //push value corresponding to reference stored in "wifi_scan_succeed" onto the stack

  if (status == OK) //if status equals OK(0) then...
  {
    struct bss_info *bss_link = (struct bss_info *)arg; //initialize a pointer to a struct containing the Access Point info("arg") that was passed to this function
    bss_link = bss_link->next.stqe_next;//ignore first entry
    lua_newtable( gL ); //create lua table, to store AP info

    while (bss_link != NULL) //while variable "bss_link" NOT EQUAL to NULL do...
    {
      c_memset(ssid, 0, 33); //set "0" to all chars in the variable "ssid"
      if (c_strlen(bss_link->ssid) <= 32) //if length of the string contained within "bss_link->ssid" is LESS THAN or EQUAL to 32 characters then...
      {
        c_memcpy(ssid, bss_link->ssid, c_strlen(bss_link->ssid)); //copy contents of "bss_link->ssid " to "ssid"
      }
      else //not sure why this here, maybe to copy only 32 characters of the string if it's longer than 32 chars
      {
        c_memcpy(ssid, bss_link->ssid, 32); //copy contents of "bss_link->ssid " to "ssid"
      }
      c_sprintf(temp,"%d,%d,"MACSTR",%d", bss_link->authmode, bss_link->rssi,
                 MAC2STR(bss_link->bssid),bss_link->channel); // copy "authmode, rssi, bssid, channel" values from variable "bss_link" to variable "temp"

      lua_pushstring(gL, temp); //set value of current key in lua table to contents of variable "temp"
      lua_setfield( gL, -2, ssid ); //set "ssid" as the key name in lua table for (current?/last?) entry in the table.  (don't get how the index(-2) works)

      // NODE_DBG(temp);

      bss_link = bss_link->next.stqe_next; // select next ssid in bss_link???
    }
  }
  else //if "STATUS" NOT EQUAL "OK(0)" then...
  {
    lua_pushnil(gL); //push nil value onto stack for pointer "gL"? not sure what exactly this does... maybe this makes sure that nothing is returned to user in case info is old or non-existent.
  }
  lua_call(gL, 1, 0); //calls user's callback function???
}


As per your suggestion I read the sections pertaining to the Lua stack in the book "Programming in Lua (first edition)", prior to this, whenever I ran across anything referring to the stack in Lua, I assumed that it was similar in definition to the stack and heap that Arduino(AVR) uses, now I think it's more like a virtual stack, could still be wrong though.
I also got the information about the Lua api functions from Here and I read about garbage collection HERE, HERE and HERE.
My source for the info on the C functions I got from HERE.
User avatar
By cal
#16072 As you may have noticed I am not a native speaker. So please correct me when I get non idiomatic.


prior to this, whenever I ran across anything referring to the stack in Lua, I assumed that it was similar in definition to the stack and heap that Arduino(AVR) uses, now I think it's more like a virtual stack, could still be wrong though.


You are right. When programming with arduino you have the processor stack which is used by the c language to
store values and pass parameters to functions etc.
Since it's the only stack its just "the stack".
I typicall call it the "c stack".
This is different from the stack you identified as "like a virtual stack" that lua uses to pass values and call functions.
In the end "virtual" is relative to the position you take so it depends.
Lets just call it "the lua stack".
The memory that is used for the lua stack is allocated from the heap with typical c "malloc"-like functions.
Normally the same that you use in your c program.
The lua stack is one of the central data structures of lua.
I suggest don't going into the implentation details of the stack first but stay on the conceptual level:

1. a stack has a stackpointer SP that point to the top of the stack
2. mostly you "push" values on the top of the stack and "pop" from the stack
3. If you address values on the stack you do it relative to the top. SP[0] is the top element SP[-1] the one below the top
and so on.

S:
push(100)
S: 100
^ SP
push(200)
S: 100 200
^SP
push(300)
S: 100 200 300
^SP
SP[0]: 300
SP[-1]: 200
SP[-2]: 100

pop()
S: 100 200
^SP
SP[0]: 200
SP[-1]: 100

Until your mind gets a "stack mode" just print current stack while following program flow on paper.

So a lua thread of execution needs a stack pointer.
Where is it?
This is where
lua_State* L
comes into play.

lua_State contains the context information needed for a lua thread and that includes the lua stack pointer.

Knowing this lets look at the code.

dnc40085 wrote:Alright, here goes...

Code: Select allstatic int wifi_station_listap( lua_State* L )
{
  if(wifi_get_opmode() == SOFTAP_MODE)  //if esp8266 operating mode is  SOFTAP then...
Yep.
Code: Select all  {
    return luaL_error( L, "Can't list ap in SOFTAP mode" ); // return error
  }
  gL = L; //copies pointer "L" to a global variable "gL" so it can be used in wifi_scan_done later
Yep.
Code: Select all  if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION){ // if index 1 of "L" is a function then...
What may index 1 be? Where may it come from?
Code: Select all
    lua_pushvalue(L, 1);  // copy argument (func) to the top of stack
Yep. Just say: push function on stack
Code: Select all
    if(wifi_scan_succeed != LUA_NOREF)// if variable(wifi_scan_succeed) is NOT equal to constant (LUA_NOREF(-2)) then...
      luaL_unref(L, LUA_REGISTRYINDEX, wifi_scan_succeed); //release previous reference and corresponding value???
Yep. (Maybe time to get suspicious?)
Code: Select all
    wifi_scan_succeed = luaL_ref(L, LUA_REGISTRYINDEX); //create reference(lua pointer) to lua value and store the ID for the reference in the variable "wifi_scan_succeed"
What is this "value"? Where is it? Where does it come from?
Code: Select all
    wifi_station_scan(NULL,wifi_scan_done); //call station scan function from SDK
Correct. Notice what is passed and what it means.
Code: Select all  } else { // if index 1 of "L" is NOT a function then...
    if(wifi_scan_succeed != LUA_NOREF) // if variable(wifi_scan_succeed) is NOT equal to constant (LUA_NOREF(-2)) then...
      luaL_unref(L, LUA_REGISTRYINDEX, wifi_scan_succeed); //release previous reference and corresponding value???
Yep. (Maybe time to get even more suspicious?)
Code: Select all    wifi_scan_succeed = LUA_NOREF; //set variable "wifi_scan_succeed" to "LUA_NOREF(-2)" since the value corresponds to a non-existent reference 
Exactly.
Code: Select all  }
}


Code: Select allstatic void wifi_scan_done(void *arg, STATUS status)
{
  uint8 ssid[33];  // Initialize variable "ssid"
Not really. It "defines" or declares the variable. The variable exists there after.
It is NOT initialialized which means "get a value". Its uninitialized. Typically contains garbage.
Note the size of the array.
Side note: memory for this local variable comes from the c stack. I will vanish
Code: Select all  char temp[128]; // Initialize variable "temp"
See above.
Code: Select all  if(wifi_scan_succeed == LUA_NOREF) //if variable "wifi_scan_succeed" contains no reference(lua pointer) then...
    return; // since there is no reference ID, return
Yep. Does that have any meaning on lua application code level?
Code: Select all  if(arg == NULL) //if variable "arg" is NULL then...
    return; //there is nothing to process so return
What is this arg? Where does it come from?
Code: Select all 
  lua_rawgeti(gL, LUA_REGISTRYINDEX, wifi_scan_succeed); //push value corresponding to reference stored in "wifi_scan_succeed" onto the stack
Yep.
What type of object is it?
Just say: push <the-type-xxx> wifi_scan_succeed on the stack
Code: Select all
  if (status == OK) //if status equals OK(0) then...
  {
    struct bss_info *bss_link = (struct bss_info *)arg; //initialize a pointer to a struct containing the Access Point info("arg") that was passed to this function
Yep.
Code: Select all    bss_link = bss_link->next.stqe_next;//ignore first entry
I agree.
Code: Select all    lua_newtable( gL ); //create lua table, to store AP info
Yep.
Code: Select all
    while (bss_link != NULL) //while variable "bss_link" NOT EQUAL to NULL do...
    {
      c_memset(ssid, 0, 33); //set "0" to all chars in the variable "ssid"
Yep.
Code: Select all      if (c_strlen(bss_link->ssid) <= 32) //if length of the string contained within "bss_link->ssid" is LESS THAN or EQUAL to 32 characters then...
      {
        c_memcpy(ssid, bss_link->ssid, c_strlen(bss_link->ssid)); //copy contents of "bss_link->ssid " to "ssid"
      }
      else //not sure why this here, maybe to copy only 32 characters of the string if it's longer than 32 chars
Look at definition of target "ssid".
Code: Select all      {
        c_memcpy(ssid, bss_link->ssid, 32); //copy contents of "bss_link->ssid " to "ssid"

Be more precise about the semantics.
Remember how c strings are defined (especially what defines the length of a c string).
Look at the definition of ssid.
Why does ssid contain a valid c string after this?
Code: Select all      }
      c_sprintf(temp,"%d,%d,"MACSTR",%d", bss_link->authmode, bss_link->rssi,
                 MAC2STR(bss_link->bssid),bss_link->channel); // copy "authmode, rssi, bssid, channel" values from variable "bss_link" to variable "temp"

"copy" is too unprecise for me.
Here may be dragons.
Based on the format string and parameters given to the function a new string is generated and written to the buffer
defined by temp.
I typically say "print xxx to buffer temp".
Side note: Can the buffer temp overflow? What would happen if it overflows?
Code: Select all
      lua_pushstring(gL, temp); //set value of current key in lua table to contents of variable "temp"

Technically it just pushes a string on the stack.
What is "current key"?
Does it have a meaning?
Code: Select all      lua_setfield( gL, -2, ssid ); //set "ssid" as the key name in lua table for (current?/last?) entry in the table.  (don't get how the index(-2) works)
Maybe backwards thinking can help. Stay tuned.
Code: Select all

      // NODE_DBG(temp);

      bss_link = bss_link->next.stqe_next; // select next ssid in bss_link???
Think of "next entry".
Code: Select all    }
  }
  else //if "STATUS" NOT EQUAL "OK(0)" then...
  {
    lua_pushnil(gL); //push nil value onto stack for pointer "gL"? not sure what exactly this does... maybe this makes sure that nothing is returned to user in case info is old or non-existent.

Think about what "gL" is used for. It's just the home for the SP.
Why push nil on the stack if we don't have anything? Why don't just leave the stack unchanged?
Code: Select all  }
  lua_call(gL, 1, 0); //calls user's callback function???
Consider the state of the lua stack, the definition (http://pgl.yoyo.org/luai/i/lua_call), explain the parameters to lua_call.
If you are confident what function it is:
What type of paremeter does it expect?
Can that help you understand the lua_setfield function?
http://pgl.yoyo.org/luai/i/lua_setfield
What do they mean with "t[k] = v" and how is that translated to the state of the lua stack and the parameters
of that function when it is called?
}
[/code]