0

I have a C program running in my Raspberry Pi. I would like to create a simple web page with one button that allows me to set a boolean variable in the C program. How do I interface with the C program from a web page?

I have searched around but can't find anything useful. Any help or sample code would be great.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Bich Pham
  • 27
  • 4
  • 3
    Why don't you post what you have done so far so we can understand what you have tried? Otherwise it will looks like a question for some homework stuff. – campescassiano Mar 23 '18 at 02:25
  • Welcome to Stack Overflow. Please read the [About] and [Ask] pages now. As it stands, this question is far too broad. What is that C program doing? Just waiting for inputs from the web page, or doing other stuff too? Is the program going to be run each time the button is pushed? If the button is pushed, does it toggle the state of the boolean, or does it always set it (to true) or reset it (to false), or what? You also haven't specified enough what you're trying to do. – Jonathan Leffler Mar 23 '18 at 05:14
  • Thank you everyone. As a complete beginner to website hobby, I was only looking for someone to point me in the correct direction. All the answers below will give me a good start. – Bich Pham Mar 25 '18 at 12:23

3 Answers3

1

If I understand you, you want to set up a Raspberry Pi Web Server with CGI enabled:

This can help you in the CGI part: https://web.ornl.gov/~ncsgroup/decode/decode_doc.html

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
1

There are lots of ways of doing this. First off, if you are a beginner with setting up webpages, I would recommend you install lighttpd instead of Apache as it is very easy to configure.

So you would do:

sudo apt-get install lighttpd php-cgi

Then save the following as lighttpd-local.conf

################################################################################
# lighttpd-local.conf
# 
# Simple config file for lighttpd without needing to install Apache or configure
# any system-wide stuff in "/etc".
#
# Allows running Perl and PHP scripts as CGI. You may need:
#
# sudo apt-get php-cgi
#
# Just start serving the current directory by running:
#
# lighttpd -f lighttpd-local.conf
# 
# And access it in your browser (Safari, Chrome, Firefox) at:
#
# http://<IP_ADDRESS>:8000
#
################################################################################
# To see your PHP settings and configured modules, create a file in this
# directory called "phpinfo.php" which contains:
#
# <?php
# phpinfo();
# ?>
#
# And then in your browser, navigate to:
# 
# http://<IP-ADDRESS>:8000/phpinfo.php
################################################################################
# Bind to all interfaces - wired, wifi and be accessible anywhere
server.bind          = "0.0.0.0"
server.port          = 8000
server.document-root = CWD
server.errorlog          = CWD + "/lighttpd.error.log"
accesslog.filename       = CWD + "/lighttpd.access.log"
server.breakagelog       = CWD + "/lighttpd.breakage.log" 

index-file.names = ( "index.php", "index.html", "index.htm", "default.htm" )

server.modules = ("mod_cgi", "mod_accesslog")

# Ensure Perl and PHP scripts are executed rather than have their contents displayed
static-file.exclude-extensions = (".pl",".php")
cgi.assign = ( ".pl"  => "/usr/bin/perl",
               ".php" => "/usr/bin/php-cgi" )

mimetype.assign = (  
  ".css"        =>  "text/css",
  ".gif"        =>  "image/gif",
  ".htm"        =>  "text/html",
  ".html"       =>  "text/html",
  ".jpeg"       =>  "image/jpeg",
  ".jpg"        =>  "image/jpeg",
  ".js"         =>  "text/javascript",
  ".png"        =>  "image/png",
  ".txt"        =>  "text/plain"
)

And finally start your web server, serving the contents of the local directory:

lighttpd -f lighttpd-local.conf

Then you want to consider how your webpage will interact with your C program. Some possibilities are:

  • via the filesystem
  • via a messaging system
  • via a database

If you want to use the filesystem, basically you make a CGI-type program that writes the variable into a file whenever the user presses a button - in the example below that file is called "setting.txt". Your C program then reads the variable from that file. It could either read the file every time through its main loop, or your CGI-type program could send your C program a signal (e.g. kill -HUP ) and it could have signal handler that re-reads the file.

So, you would save this as index.php:

<?php
// If we were POSTed, save the value in file on server for C program to see
if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
   file_put_contents("setting.txt",$_POST['val']);
   // *** MARKER ***
   return;
}
?>
<html>
<head>
  <title>Simple Control</title>
  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>

<?php
   // PHP - executed on server before webpage is loaded
   // Get setting from previous run to pass to Javascript
   $s = file_get_contents("setting.txt");
   $s = intval($s);
?>

<script type="text/javascript">
    // Javascript - executed on client in browser

    // Put PHP variable into Javascript global
    var gblSetting=<?php echo $s; ?>;

    // This function is run when webpage is loaded
    $(document).ready(function() {

       // Display current value on webpage
       $("#idCurrent").html("Current value: " + gblSetting);

       // This function is run when button is clicked
       $('#idButton').click(function()
       {
          // Toggle the global Javascript variable
          gblSetting=1-gblSetting;

          // Send its new value to server to save for C program to see
          // See POST code at start of this file
          $.ajax({
            type: 'POST',
            url: 'index.php', 
            data:'val='+ gblSetting
          })

          // Update value on webpage
          $("#idCurrent").html("Current value: " + gblSetting);
       });
    });
</script>
</head>

<body>
<p>
<div id="idCurrent">Unknown</div>
<button id="idButton">Toggle value</button>
</p>

</body>
</html>

and then navigate in your browser to:

http://<IP_ADDRESS>:8000/index.php

If you have got everything correct, it will look like this:

enter image description here

If you wanted to send a signal to your C program whenever the file changes, you would go to the line with *** MARKER *** and insert a call to kill. Then set up a signal handler in your C program that handles SIGHUP for example. Signal handler setup is described here. Here is a quick example:

#include <unistd.h>
#include <chrono>
#include <thread>
#include <csignal>
#include <iostream>

int nSignals;

void signal_handler(int signal)
{
   std::signal(SIGHUP, signal_handler);
   std::cout << "Got signal" << std::endl;
   nSignals++;
}

int main()
{
   // Install a signal handler
   std::signal(SIGHUP, signal_handler);

   std::cout << "Send me a signal with: kill -HUP " << (int)getpid() << std::endl;

   while(nSignals<5){
      std::cout << "Received " << nSignals << " of 5 signals, sleeping..." << std::endl;
      std::this_thread::sleep_for(std::chrono::seconds(5));
   }
}

If you want to use a messaging program, your C program would subscribe to a messaging system (nanomsg, zeromq, mosquitto) and your CGI-type program would send a message when the user clicks a button. You would insert that code into the above file where it says *** MARKER ***.


If you want to use a database (e.g. sqlite is small and easy, or Redis is small and easy), your C program would read its values from the database and your CGI-type program would write the value in the database when the user clicks a button. You would insert that code into the above file where it says *** MARKER ***. So, if you used Redis, that code might be something like:

$redis->connect('127.0.0.1'); // port 6379 by default
...
$redis->set('value', 1);

Then in your C program, you use hiredis and code like this to retrieve the current value:

redisContext *c = redisConnect("127.0.0.1", 6379);
reply = redisCommand(c,"GET value");
printf("GET value: %s\n", reply->str);

Here is a link to a Redis-type of setup that could be adapted.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • Thanks for the detailed example. If I have a program that looks like below. How do I use posix_kill and signal handling to toggle the variable "button" in c #include #include bool button = 0; //I would like to toggle this variable from a website int main() { return 0; } – Bich Pham Mar 28 '18 at 17:41
  • Please add any code into your original question by clicking `edit` underneath the original question - it is too hard to read in the comment area. – Mark Setchell Mar 28 '18 at 17:51
  • I don't understand. Is your comment a new question? My answer already shows you how the value in the file `setting.txt` changes when you click the button on the website. Your program should read that file when it wants the current value. – Mark Setchell Mar 28 '18 at 17:53
  • Sorry I was trying to delete that comment but it would not let me. I was trying to find an example on how to read the file "setting.txt" in c. Also I'm looking for example on the call to kill as well. – Bich Pham Mar 28 '18 at 18:22
  • You can read a value from a file in C like this https://stackoverflow.com/a/12944846/2836621 – Mark Setchell Mar 28 '18 at 18:34
  • I have added code into the answer to show you a signal handler. – Mark Setchell Mar 28 '18 at 18:40
0

Wow! This is loaded question!

First of all you have to create a web page. Do not reinvent the wheel. You have a lot of good frameworks which can do the heavy lifting. You can use Python based Flask, you can use JavaScript Node.js, and so on...

Once you have a web page, you have to communicate with your program. Once again lots of choices. If I were you, I would use nanomsg which has bindings to Python, JavaScript (Node.js), Java, C# and so on.

As for the sample code check nanomsg for node.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
sg7
  • 6,108
  • 2
  • 32
  • 40
  • IMO you are overcomplicating this thing. Flask and node.js are needed only if you need server side stuff besides the "setting a bool variable in my C program", otherwise you can do perfectly well with a static page, possibly with a bit of JavaScript, and a CGI, as it was done back in the 90s; no need to get bogged down in lots of dependencies for simple stuff. For anything more complicated, I would decide for a platform (be it Python+flask or whatever) and stick to it, without introducing messaging, marshaling & co unless strictly necessary. – Matteo Italia Mar 23 '18 at 07:15
  • @MatteoItalia Thank you for you comment. You are very right, as you pointed out, for something very simple not much is needed. – sg7 Mar 23 '18 at 13:44