Initial commit
[jamendo] / branches / nota-show-app / src / pdu.c
1 /***************************************************************************
2  *            pdu.c
3  *
4  *  Thu Nov 19 15:13:08 2009
5  *  Copyright  2009  Marcin Miklas
6  *  <marcin.miklas@teleca.com>
7  ****************************************************************************/
8 #include <string.h>
9 #include <netinet/in.h> 
10 #include <stdlib.h>
11 #include "notaio.h"
12 #include "pdu.h"
13
14 ServiceMessage* pack_pdu(int sigid, uns8* payload, int payload_len, int* pdu_len) {
15 /* Now we need to construct a Service Message to send to the Hello, world
16  * service at the other end. Our service message will look like this:
17                                                                 ARGUMENT  ITEM
18 0xA1            SIGID   0x41            LENGTH          DATA
19 Length of       8 bit   Argument        Length          Data
20 signal ID       sigid   type            of data         field
21
22  * Ok, so what exactly does all this mean? Let's go through it one
23  * field at a time:
24  * - 0xA1: this is the length of the following signal ID. 0xA1 means
25  *   it will be 1 byte long (8 bits).
26  * - SIGID: Signal Identifiers are used by service nodes to recognize 
27  *   incoming signals (messages). A list of valid signals should be
28  *   provided in the Service Interface Specification.
29  * - 0x41: Type of the following argument, or one of NULL, TRUE or
30  *   FALSE for simple items where these values are enough.
31  * The bytes following the argument type field make up the value of
32  * the argument. For example, an argument type of 0x14 (unsigned 32-bit
33  * integer) is followed by 4 bytes of data, representing the integer
34  * value in question. In our case, the argument type is 0x41, which
35  * stands for binary data (in our case, the test string we will be
36  * sending). For binary data items such as strings, the argument item
37  * is further divided into two parts:
38  * - LENGTH: Length of the following binary data, in octets. This is an
39  *   8 bit value, so the maximum length is 255 octets. For longer items,
40  *   use type 0x42, which has a 16-bit length field.
41  * - DATA: The amount of data specified by LENGTH.
42  *
43  * For more information about Service Messages, see Appendix D of the
44  * NoTA platform programming guide.
45  */
46         if (!payload) payload_len = 0;
47         ServiceMessage* smsg = (ServiceMessage*)malloc( SERVICE_MESSAGE_HEADER_LEN + payload_len );
48         smsg->sigid_length = 0xA1;
49         smsg->sigid[0] = sigid;
50         smsg->argtype = payload ? 0x42 : 0x01;
51         smsg->arglen = htons(payload_len);
52
53         if (payload) {
54                 memcpy(smsg->argdata, payload, payload_len);
55         }
56
57         if (pdu_len) {
58                 *pdu_len = SERVICE_MESSAGE_HEADER_LEN + payload_len;
59                 if(!payload)
60                         *pdu_len -= sizeof(smsg->arglen);
61         }
62
63
64         return smsg;
65 }
66
67 /* If we decide to discard a message before it is fully
68  * read, we'll need to
69  * have some way of abandoning remaining data on the
70  * connected socket.
71  * This function serves that purpose for the time being
72  * (that is, until HIN3 supports message-based sockets).
73  */
74 static void clear(HSSockID socket,int quiet, ServiceCallbacks* cb)
75 {
76         uns8 buf[64];
77     HErrorCode err;
78         int i=0;
79     do {
80         err = n_read(socket, &buf, 64, HSReceiveNonBlocking);
81                 if (!quiet) {
82                         while (i < 64) {
83                                 LOG1("%02x ", buf[i++]);
84                         }
85                 }
86     } while (err > 0);
87         if(!quiet)
88                 LOG("\n");
89 }
90
91 HErrorCode read_smsg(HSSockID* socket, HSReceiveMode mode, ServiceCallbacks* cb)
92 {
93         HErrorCode error;
94         ServiceMessage smsg;
95         int count = 0;
96         
97         /* In the following lines, we will read the service message from
98          * the internal RX buffer into the 'smsg' variable. The first bytes 
99          * of a NoTA service message will tell us what kind of message 
100          * we're dealing with.
101          */
102     error = n_read(*socket, &smsg.sigid_length, sizeof(smsg.sigid_length), mode);
103         if (error <= 0)
104                 return error;
105         count += error;
106         if (smsg.sigid_length != 0xA1)
107         {
108                 //LOG("Only 8-bit signal identifiers currently recognized.\n");
109                 clear(*socket, 1, cb);
110                 return 0;
111         }
112         error = n_read(*socket, &smsg.sigid, 2, mode);
113         if (error <= 0)
114                 return error;
115         count += error;
116         switch(smsg.sigid[0]) 
117         {
118         case PUT_IMAGE:
119                 {
120                         error = n_read(*socket, &smsg.argtype, 1, mode);
121                         if (error <= 0)
122                                 return error;
123                         if (smsg.argtype != 0x42)
124                         {
125                                 clear(*socket, 0, cb);
126                                 return 0;
127                         }
128                         error = n_read(*socket, &smsg.arglen, 2, mode);
129                         smsg.arglen = ntohs(smsg.arglen);
130                         if (error <= 0)
131                                 return error;
132                         uns8* argdata = malloc(smsg.arglen);
133                         error = n_read(*socket, argdata, smsg.arglen, HSReceiveBlocking);
134                         if (error == smsg.arglen)
135                         {
136                                 if(cb->put_image)
137                                         cb->put_image(argdata,smsg.arglen);
138                         }
139                         else
140                         {
141                                 LOG2("Error: got only %d bytes of %d expected.\n", error, smsg.arglen);
142                         }
143
144                         free((void*)argdata);
145                 }
146                 break;
147         case GET_IMAGE:
148                 error = n_read(*socket, &smsg.argtype, 1, mode);
149                 if (error <= 0)
150                         return error;
151                 if (smsg.argtype != 0x01)
152                 {
153                         clear(*socket, 0, cb);
154                         return 0;
155                 }
156                 {
157                         uns8* last_img=NULL;
158                         int last_img_size=0;
159
160                         ServiceMessage* smsg;
161                         int smsg_len=0;
162
163                         if (cb->get_image) {
164                                 last_img = cb->get_image(&last_img_size);
165                         }
166                                                 
167                         smsg = pack_pdu(PUT_IMAGE, last_img, last_img_size, &smsg_len);
168                         error = n_send(*socket, smsg, smsg_len, HSSendBlocking);
169                         free(smsg);
170
171                         free(last_img);
172                 }
173                 break;
174         case FACE_FOUND:
175                 {
176                         error = n_read(*socket, &smsg.argtype, 1, mode);
177                         if (error <= 0)
178                                 return error;
179                         if (smsg.argtype != 0x42)
180                         {
181                                 clear(*socket, 0, cb);
182                                 return 0;
183                         }
184                         error = n_read(*socket, &smsg.arglen, 2, mode);
185                         smsg.arglen = ntohs(smsg.arglen);
186                         if (error <= 0)
187                                 return error;
188                         
189                         struct {int x,y,r;} face;
190                         error = n_read(*socket, &face, sizeof(face), HSReceiveBlocking);
191                         if (error == smsg.arglen) {
192                                 if(cb->face_found) {
193                                         cb->face_found(ntohl(face.x),ntohl(face.y),ntohl(face.r));
194                                 }
195                         }
196                 }
197                 break;
198         case DISCONNECT:
199                 if (cb->disconnect) {
200                         cb->disconnect(*socket);
201                 }
202                 return DISCONNECT;
203                 break;
204         case QUIT:
205                 if (cb->quit) {
206                         cb->quit(*socket);
207                 }
208                 return QUIT;
209                 break;
210         default:
211                 LOG("Unsupported service call.\n");
212                 clear(*socket, 0, cb);
213                 break;
214         }
215         return 0;
216 }