An archive of community.esquilo.io as of Saturday January 26, 2019.

ERPC Issues and workarounds

gwittie

I have been struggling to get the ERPC interface working with my nut file and have uncovered a few issues that took a long time to resolve.
1. Large code size of the nut file may not allow space for ERPC to run. I have a large nut file built to run as a stand-alone thermal controller with LCD display, 2 one-wire thermocouples, 2 heater control SCR relays, buzzer, and an analog temp sensor. The issue was ERPC would not communicate with my html page until I pared down the size of the nut file to a bare-bones operation. Once this was done, the RPC communication would then work.
2. RPC passed parameters did not behave the same in stand-alone mode compared to RPC passed values. The problem was the values passed by RPC must be string text and the nut file did not automatically convert them to integer, float or boolean values. I had to force the conversion with param.tointeger; param.tofloat, and if (param == "false") newparam = false; else newparam = true; After this conversion, the controller operated the same as the stand-alone mode.

I would like to call the html page from the nut file to initiate data transfer to a html graph rather than poll the nut file from the html page. Can this be done? I cannot find an example of this being done.

I hope this will help others when they use html with nut files and the ERPC interface.
If I find any other issues and work-arounds, I will add to this topic.

Scott_Shumate

Thanks for the feedback.

On point 1., you do have to be mindful of memory usage with larger applications. Turning off unused network services and using the new require() function in EOS 0.3 along with turning off all Squirrel libraries can help a lot. Normally, ERPC doesn't require much free memory to run so I wonder if you were running into a separate issue.

On point 2., ERPC parameters are passed to the Squirrel functions using the same data type as the corresponding JSON. So if you pass an integer, you'll get an integer. If you pass a string, you'll get a string. Here's an example. Suppose you had this ERPC Squirrel function:

function gettype(params)
{
    return typeof params;
}

If you pass true without quotes, it will be a bool:

curl -d '{"method":"gettype", "params":true}' http://10.0.0.196/erpc
{"result":"bool"}

But if you pass it quoted, it will be a string:

curl -d '{"method":"gettype", "params":"true"}' http://10.0.0.196/erpc
{"result":"string"}

The same thing goes for integers and other types:

curl -d '{"method":"gettype", "params":123}' http://10.0.0.196/erpc
{"result":"integer"}
curl -d '{"method":"gettype", "params":"123"}' http://10.0.0.196/erpc
{"result":"string"}

On your last question about initiating data transfer from the nut, the typical way to do asynchronous events with web servers is either with long polling or websockets. Long polling with ERPC won't work because it will block the Squirrel thread. We have added websocket support to the web server but we don't have it hooked up to Squirrel yet. It's on the TODO list.

gwittie

Scott, Thanks for your response.
On item 1, I cannot turn off many of the system functions since I use a variety of hardware
which requires different firmware. I did generate reduced driver code for my One-wire interface which helped. I am working on a fix for my app by moving some code out of the current javascript and nut files to be able to edit parameters so they do not bloat my controller code. Hopefully this will resolve the memory usage issue that I have.

On item 2, you are correct in the parameter types being handled by the ERPC interface. My issue stemmed from getting parameter data from html text boxes, checkbox and button value statements and passing the selections directly thru ERPC to the nut file. Once I did the type conversion from text to boolean or integer in the javascript code, the nut file received the correct format. I have not tried this for the float numbers yet.

On the last topic, I have not had time to investigate whether there are any issues with calling the nut file at random times in my control loop. I have to resolve the other issues from steps 1 and 2 in addition to a new hardware problem that cropped up this weekend on my LCD display interface. If anything note-worthy comes out of this investigation, I'll pass it along.

gwittie

I have a few more questions regarding the ERPC interface. My thermal control application has been pared down to minimum functionallity so that it does not reset the Esquilo board constantly. It is a lot better but will reset the board after a few times of running the nut/html code. Is there a log file that I can review that would indicate the processes that are not being closed out and filling up the available memory?

Also, can you explain the ERPC process in more detail? My html code will call a nut function that could run for a few seconds to hours depending on the profile setup stored in NV memory. During this long running function, I need to have the html code poll the nut file to get the status and display this in the browser window. It currently does not pull the status array and I cannot get the information for the javascript to operate on. Does the status polling ERPC call get blocked by the long running ERPC call? or can it run asynchronously? I initially did not set the EPRC timeout parameter and my long running function would stop at 10 sec (default time). I finally added the cum time for the process to ERPC timeout parameter and it runs the entire time but I still do not get status information back. I have used setTimeout and setInterval commands to try to get the status data every 2 seconds but it is not working with the long running ERPC. It runs just fine in an offline mode and before and after the long-running function call.

Any help with this would be appreciated.

Scott_Shumate

To check the tasks and memory, use "eos task" and "eos memory". You can either run these from the EOS shell in a Telnet session or USB console or you can run them from the IDE by using the system() function i.e. system("eos task"). There is a log command also but it won't tell you anything about the tasks and memory.

There is only one thread running in the Squirrel VM. When you make a ERPC request, the Squirrel VM thread will process it the next time it executes the delay() function. If the ERPC request does not return, then it will hold the Squirrel VM thread hostage until it does. It is best to make the ERPC requests very short and do your heavy lifting in the main program. In the ERPC function, you could set a flag or append to a queue and let your main thread act on it when the ERPC returns. If your main thread is going to take a while processing it, then sprinkle some delay() functions in its processing loop to give it the opportunity to process ERPC commands. You can use delay(0) which will process pending ERPC without waiting.

gwittie

Thanks for this explanation of RPC.
Combining this with a RPC description paragraph in the web site, https://www.cs.rutgers.edu/~pxk/417/notes/03-rpc.html ...

In 1984, Birrell and Nelson devised a mechanism to allow programs to call procedures on other machines. A process on machine A can call a procedure on machine B. When it does so, the process on A is suspended and execution continues on B. When B returns, the return value is passed to A and A continues execution. This mechanism is called the Remote Procedure Call (RPC). To the programmer, it appears as if a normal procedure call is taking place. Obviously, a remote procedure call is different from a local one in the underlying implementation.

I assume your implementation follows this description of RPC operation. If so, both descriptions explain my problems. With trying to run another RPC call when the previous RPC call had not finished (since it could run a long time). Also the memory issue was probably caused by my code reissuing an RPC call if the previous one did not complete. So, there were many unprocessed RPC calls left hanging in memory.

I am in the process of rebuilding my process code to follow your suggestion. It will take a few days to get it worked out. Hopefully this will get me going again.

Scott_Shumate

That description is pretty accurate to what ERPC is doing. The only difference is that if A is your web browser, then it is not suspended and it continues doing other things until the response from B (Esquilo) comes back.

gwittie

If that is the case with a browser, then what happens when the response from the Esquilo comes back? Does it go back to the the ERPC call and re-continues at that point or does it handle the returned data with the pass function or error function, and then jumps back to where it left off?

Scott_Shumate

If you are using the erpc.js library, then the third parameter is the function to call when the ERPC response comes back. For example, in JavaScript you could write:

erpc("myFunction", [1, 2, 3], function(result) { console.log("Esquilo response:" + result); });

The erpc function will transmit the ERPC call for myFunction([1, 2, 3]) to Esquilo and immediately continue running any JavaScript code that follows the erpc function before receiving Esquilo's response. When the Esquilo does return the response to the web browser, the JavaScript function given as the third parameter is called at that point. When that function returns, Javascript will continue doing whatever it was doing when the response came back.

gwittie

Thank you. This will help me with my javascript coding. I think I still need to modify my polling loop to not get into another memory hog situation.

robertjensen

Just for fun, I was playing around with transferring a large file from the Esquilo to a javascript array. What I was doing might be relevant here.

I made a ERPC call that started the transfer process on the Esquilo side. The Esquilo would return a chunk of data. It could have returned status instead of data if the task is processing rather than data transfer. In javascript, the response function would capture the new chunk of data and display proress. That function would end with a javascript call to setTimeout to call ERPC again in 2 ms if the task is not complete. At that point, work on the Equilo side would resume for the next chunk of data. That way, progress was being displayed while the transfer was taking place. Also, I could transfer more data than the Esquilo needs to hold in memory at any given time.

With this approach, the Esquilo is not working 100% of the time on whatever task it has, but it could be close to 100% depending on how often this back-and-forth takes place. That is completely controlled on the Esquilo side. The browser gets regular updates without polling.

Transferring a file from the Esquilo to the browser with xmlhttprequest is WAY faster, so what I did was not useful for file transfer. The outline might be useful for a CPU-bound task that can be paused at intervals and then resumed.

gwittie

Interesting approach for long running ERPC calls. In my situation, it would not apply since I needed real-time monitoring and control over a multi-level temperature profile that could take minutes to hours to perform. I fixed my problem by assuming the javascript in the html page would continue to run during the Esquilo processing and only used returned status/data to the javascript script to display status and determine the completion of the task to call the completion functions. I am at the limit of the Esquilo memory with my nut file size and html page size. I will next try to load with the boot.nut file and see how much more code/features that I can add until I run out of memory again.