Welcome to SIMPL Programming for Python
Lesson #4

Course content Enter chat room Send email 
to mailing list
Check calendar

Lesson Overview

In this lesson we are going to examine the detailed workings of a python gui-based sending  program and a C coded receiving program.

The sender program is able to send three different types of messages and the receiver program to receive these messages and react appropriately.

The sender program in this lesson has a gui instead of a textual interface. The sending of the various messages are initiated by clicking on the various message buttons.

The messages are exactly the same as in Lessons #2 and #3.

The receiver program prints to screen the various components of the messages received.

The receiver program is exactly the same one as in Lesson #3.

With this algorithm, we hope to demonstrate the following:

  1. how a gui-based python program can be made to communicate with a C program

 

Note:

Do NOT cut and paste the following code pieces. The scripts are available in the .../src directory for you to run directly.

Let's examine the sending script.

The following code can be found in the ../src/sender_gui3.py file. We will examine it line by line.
 
      1 """
      2 sender_gui.py: This is a python simpl gui-based sender.
      3 Refer to lesson #4.
      4 Usage: python sender_gui.py
      5 """
      6 
      7 
      8 # import necessary modules
      9 import sys
     10 import csimpl
     11 from tkinter import *
     12 
     13 nee = None
     14 
     15 # define the callback for button 1
     16 def hndlButton1(event):
     17         token = 10
     18         a = 99
     19         b = 999
     20         c = 9999
     21         nee.packMsg(nee.BIN, "iiii", token,a,b,c)
     22         makeSend()
     23 
     24 # define the callback for button 2
     25 def hndlButton2(event):
     26         token = 20
     27         d = 3.1415
     28         nee.packMsg(nee.BIN, "if", token,d)
     29         makeSend()
     30 
     31 # define the callback for button 3
     32 def hndlButton3(event):
     33         token = 30
     34         s = "We are the knights who say Neee."
     35         l = len(s)
     36         nee.packMsg(nee.BIN, "iis", token,l,s)
     37         makeSend()
8 
     39 # define the call for the simpl send
     40 def makeSend():
     41         retVal = nee.send(receiverId)
     42         if retVal == -1:
     43                 print ("%s: send error-%s" %(sName, nee.whatsMyError()))
     44                 sys.exit(-1)
     45 
     46 # define the exit call
     47 def die(event):
     48         sys.exit(0)
     49 
     50 # initialize some required variables
     51 sName = "SENDER"
     52 rName = "RECEIVER"
     53 
     54 # create an instance of Simpl
     55 nee = csimpl.Simpl(sName, 1024)
     56 if nee == -1:
     57         print ("%s: name attach error-%s" %(sName, nee.whatsMyError()))
     58         sys.exit(-1)
     59 
     60 # name locate the receiver
     61 receiverId = nee.nameLocate(rName)
     62 if receiverId == -1:
     63         print ("%s: name locate error-%s" %(sName, nee.whatsMyError()))
     64         sys.exit(-1)
     65 
     66 # initialize Tk for graphics
     67 root = Tk()
     68 
     69 # set up a button to initiate the sending of message token type 10
     70 button = Button(root)
     71 button["text"] = "send message token type 10"
     72 button.bind("", hndlButton1)
     73 button.pack()
     74 
     75 # set up a button to initiate the sending of message token type 20
     76 button = Button(root)
     77 button["text"] = "send message token type 20"
     78 button.bind("", hndlButton2)
     79 button.pack()
     80 
     81 # set up a button to initiate the sending of message token type 30
     82 button = Button(root)
     83 button["text"] = "send message token type 30"
     84 button.bind("", hndlButton3)
     85 button.pack()
     86 
     87 # set up a button for program exit
     88 button = Button(root)
     89 button["text"] = "Exit"
     90 button.bind("", die)
     91 button.pack()
     92 
     93 # handle user input
     94 root.mainloop()

Line 10 imports the csimpl module for SIMPL capability.
Line 13 sets a global variable which will become a an instance of Simpl further on.
Lines 15-22 define a callback function that builds an outgoing message composed of an integer token and three other integers. The integer packing routines are called as instance methods and the packing type is binary because the message is being sent to a C program. Finally, the makeSend call performs the actual SIMPL Send.
Lines 24-37 define callback functions for other messages in a similar way as the one above.
Lines 51-52 define the unique SIMPL names which are treated as constants.
Line 55 creates the Simpl instance used to refer to all things Simpl in this program.
Lines 61-64 perform the simpl name locate.
Line 67 initializes Tkinter and loads the root variable with the required information for the root window.
Lines 69-73 create a button widget with text and define the function callback to be carried out in the case this button is selected. When this button is clicked on by the user a message with token type 10 will be sent to the receiver program.
Lines 75-79 create a button for sending messages of token type 20 to the receiver program.
Lines 81-85 create a button for sending messages of token type 30 to the receiver program.
Lines 87-91 create a button that allows the user to exit gracefully from the script.
Line 94 creates an infinite event loop on the root window that awaits incoming events (in this case mouse clicks on the various buttons).

Let's examine the receiving program. Note: this is exactly the same receiving program used in Lesson #3.

1. /*
2. FILE: receiver.c
3. DESCRIPTION: This is a C simpl receiver.
4. Refer to lessons 3, 4, 6, 7.
5. USAGE: receiver
6. */
7.
8. // include required headers
9. #include <stdio.h>
10. #include <stdlib.h>
11. #include <simpl.h>
12.
13. // define possible message structures
14. typedef struct
15.     {
16.     int token;
17.     int var1;
18.     int var2;
19.     int var3;
20.     } MSG1;
21.
22. typedef struct
23.     {
24.     int token;
25.     float var1;
26.     } MSG2;
27.
28. typedef struct
29.     {
30.     int token;
31.     int var1;
32.     char var2[34];
33.     } MSG3;
34.
35. int main()
36. {
37. char *me = "RECEIVER";
38. char *sender;
39. char mem[1024];
40.  int n;
41. MSG1 *in1;
42. MSG2 *in2;
43. MSG3 *in3;
44. int *token;
45.
46. // perform simpl name attach
47. if (name_attach(me, NULL) == -1)
48.     {
49.     printf("%s: cannot attach name-%s\n", me whatsMyError());
50.     exit(-1);
51.     }
52.
53. while (1)
54.     {
55.     // receive incoming messages
56.     n = Receive(&sender, mem, 1024);
57.     if (n == -1)
58.         {
59.         printf("%s: Receive error-%s\n", me, whatsMyError());
60.         continue;
61.         }
62.
63.     // set a pointer to the value of the message token
64.     token = (int *)mem;
65.
66.     // decide course of action based on the value of the token
67.     switch (*token)
68.         {
69.         case 10:
70.             in1 = (MSG1 *)mem;
71.             Printf("token=%d var1=%d var2=%d var3=%d\n",
72.            & nbsp;    in1->token,
73.            & nbsp;    in1->var1,
74.            & nbsp;    in1->var2,
75.            & nbsp;    in1->var3);
76.             break;
77.
78.         case 20:
79.             in2 = (MSG2 *)mem;
80.             printf("token=%d var1=%d\n",
81.            & nbsp;    in2->token,
82.            & nbsp;    in2->var1);
83.             break;
84.
85.         case 30:
86.             in3 = (MSG3 *)mem;
87.             printf("token=%d var1=%d var2=%.*s\n",
88.                  in3->token,
89.            & nbsp;    in3->var1,
90.            & nbsp;    in3->var1,
91.            & nbsp;    in3->var2);
92.             break;
93.
94.         default:
95.             printf("%s: unknown message token=%d\n", me. token);
96.         }
97.
98.     // reply to sender
99.     Reply(sender, NULL, 0);
100.   }
101.
102. return(0);
103. }

Lines 9-11include the required C header files. Note the inclusion of the simpl.h header file.

Lines 14-20
define the binary message that corresponds to token value 10.

Lines 22-26
define the binary message that corresponds to token value 20.

Lines 28-33
define the binary message that corresponds to token value 30.

Line 35
is the start of the program.

Lines 37-44
declare necessary local variables.

Lines 47-51
handle the simpl name attach.

Line 53
starts an infinite loop which awaits incoming messages.

Lines 56-61
receive the incoming messages.

Line 64
sets a pointer to the incoming message token.

Lines 67-96
deal with each message type based on the token by printing the various message components to the screen.
Line 99 replies a null message to the blocked sender. This reply message could be anything at all but in the interests of simplicity, the reply message has been made null.

 
 

The Makefile for the C receiver program.

The receiver program must be compiled and linked before it can be of any use. Go to ../src and at the command prompt type:

make clean
Then type:
make install
This makes a new executable of receiver.c called receiver and puts it in ../bin .
 
 

Note:

In order to run this Makefile, the shell variable SIMPL_HOME must be set so that the make can find the simpl header and library.

 
 

Let's run the two programs.

In order to run the sender_gui3.py script and the C receiver program, do the following:

  1. make sure that PYTHONPATH has been exported to your shell.
    ie. export PYTHONPATH=$(SIMPL_HOME)/python/modules
  2. open a shell window. This can be opened from a desktop such as KDE or GNOME.
  3. in this shell window,  change directory to ../bin.
  4. start the C receiver program. That is at the command line prompt type:  receiver
  5. open another shell window next to the first one.
  6. change directory to ../src.
  7. this time, run the sender program. That is,  at the command prompt type: python3 sender_gui3.py


The command indicates:

  1. the python interpreter is to run this script,
  2. the script to run is sender_gui3.py,
  3. the name of the receiver program is RECEIVER.


You should see the receiver program print the contents of each message as you choose the various message buttons displayed by the sender gui.

Let's rerun with the C receiver in the Linode cloud.

The SIMPL surrogates come in matching sets which must be run on each end of the TCP/IP link. To enable this on your end you need to run the following SIMPL daemons in the background first:

protocolRouter &
surrogateTcp &

The C receiver running on the Linode is identical to the code listed here. However in order to make the output visible via a browser the C receiver has been piped to a filter program which in turn wraps the output in HTML for perusal at:

http://icanprogram.ca/course/creceiver.html

In addition you will need to change line 52 in sender_gui.py to point at the Linode as follows:

50. # initialize some required variables
51. sName = "SENDER"
52. rName = "icanprogram.ca:RECEIVER"

and then rerun sender_gui3.py exactly as before.

Notice what happened here:

The cloud based instance C receiver which has identical code to the instance we accessed locally has now been accessed remotely. The only change in the sender was the addition of the cloud URL (icanprogram.ca) in the SIMPL name for the receiver.

 
 

Summary

Let's summarize what you should have observed in this lesson:

End of Lesson 4.


Copyright of iCanProgram Inc.  2012