Main Page | Data Structures | File List | Data Fields | Globals | Related Pages

application.c

Go to the documentation of this file.
00001 /***
00002  * This file is part of OpenHome, an open source home automation system.
00003  * Copyright (C) 2003 Jan Klötzke
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00137 #include <avr/io.h>
00138 #include <avr/pgmspace.h>
00139 #include <avr/eeprom.h>
00140 #include <inttypes.h>
00141 #include <stddef.h>
00142 #include "net/application.h"
00143 #include "net/network.h"
00144 #include "net/link.h"
00145 #include "net/buffers.h"
00146 #include "net.h"
00147 #include "utils.h"
00148 
00149 // local type definitions
00155 typedef struct {
00156                 net_addr_t addr;                
00157                 enum tsp_service_e service;     
00158                 uint8_t assoc;                  
00159         } event_desc_t;
00160 
00164 typedef struct {
00165                 uint8_t id;     
00166                 uint8_t obj;    
00167                 uint8_t method; 
00168         } assoc_t;
00169 
00173 typedef struct {
00174                 uint8_t obj;
00175                 uint8_t event;
00176         } event_t;
00177 
00178 // forward definitions for local object functions
00179 static void __sys_obj_method(void *self, uint8_t property, uint8_t *buf, uint8_t *result, uint8_t repeated);
00180 static param_desc_t __sys_obj_prop[];
00181 
00182 #ifdef APP_STATIC
00183         #define READ_WORD(x)    pgm_read_word(&(x))
00184         
00185         // system object
00186         static struct AppObject PROGMEM __sys_obj = {__sys_obj_prop, NULL, __sys_obj_method};
00187 
00188         // generate list of external object references
00189         #define OBJECT(x, y)    extern struct AppObject PROGMEM x;
00190         APP_OBJECTS
00191         #undef OBJECT
00192 
00193         // allocate eeprom for events
00194         #define OBJECT(x, y)    event_desc_t x##_ev[y] EEPROM;
00195         APP_OBJECTS
00196         #undef OBJECT
00197 
00198         // generate application object table
00199         #define OBJECT(x, y)    ,&x
00200         static const struct AppObject *  PROGMEM app_object_table[] = {&__sys_obj APP_OBJECTS};
00201         #undef OBJECT
00202         
00203         // generate event table
00204         #define OBJECT(x, y)    ,x##_ev
00205         static event_desc_t * PROGMEM events_table[] = {NULL APP_OBJECTS};
00206         #undef OBJECT
00207 #else
00208         #define READ_WORD(x)    (x)
00209         extern char __eeprom_end;
00210 
00211         // system object
00212         static struct AppObject __sys_obj = {__sys_obj_prop, NULL, __sys_obj_method};
00213         
00214         // tables
00215         static struct AppObject * app_object_table[16];
00216         static event_desc_t *events_table[16];
00217         
00218         static uint8_t next_obj = 1;
00219         void *next_eeprom_addr = &__eeprom_end;
00220 #endif
00221 
00222 // assiciation table
00223 assoc_t ee_assoc[APP_MAX_ASSOC] EEPROM;
00224 
00225 // sending network buffer
00226 static net_buf_t buffer_info;
00227 static struct main_buf_t {
00228                 uint8_t header[13];
00229                 uint8_t data[APP_BUFFER_SIZE];
00230         } buffer;
00231 static uint8_t lock;
00232 
00233 // event ring buffer (pre increment)
00234 static event_t  event_buffer[APP_MAX_EVENTS];
00235 static uint8_t event_rd, event_wr;
00236 static net_addr_t dest;
00237 
00238 /***
00239  * System network management object.
00240  */
00241 
00242 #define SYS_ADDR_LOGIC_SET      0
00243 #define SYS_ADDR_LOGIC_GET      1
00244 #define SYS_ADDR_GROUP_SET      2
00245 #define SYS_ADDR_GROUP_GET      3
00246 #define SYS_SIZE_SEGMENT_SET    4
00247 #define SYS_SIZE_SEGMENT_GET    5
00248 #define SYS_SIZE_GROUP_SET      6
00249 #define SYS_SIZE_GROUP_GET      7
00250 #define SYS_ASSOC_SET           8
00251 #define SYS_ASSOC_GET           9
00252 #define SYS_GET_ERROR_STATS     10
00253 
00254 static param_desc_t __sys_obj_prop[] = {{2,0}, {0,2}, {3,0}, {1,2}, {1,0},
00255         {0,1}, {2,0}, {1,1}, {4,0}, {1,3}, {0,8}};
00256 
00257 static void __sys_obj_method(void *self, uint8_t method, uint8_t *buf, uint8_t *result, uint8_t repeated)
00258 {
00259         switch (method) {
00260                 case SYS_ADDR_LOGIC_SET:
00261                         net_set_logic_addr(*((uint16_t*)buf));
00262                         break;
00263                 case SYS_ADDR_LOGIC_GET:
00264                         *(uint16_t*)result = net_get_logic_addr();
00265                         break;
00266                 case SYS_ADDR_GROUP_SET:
00267                         net_set_group_addr(buf[0], *((uint16_t*)(buf+1)));
00268                         break;
00269                 case SYS_ADDR_GROUP_GET:
00270                         *((uint16_t*)result) = net_get_group_addr(buf[0]);
00271                         break;
00272                 case SYS_SIZE_SEGMENT_SET:
00273                         tsp_set_segment_size(buf[0]);
00274                         break;
00275                 case SYS_SIZE_SEGMENT_GET:
00276                         *result = tsp_get_segment_size();
00277                         break;
00278                 case SYS_SIZE_GROUP_SET:
00279                         tsp_set_group_size(buf[0], buf[1]);
00280                         break;
00281                 case SYS_SIZE_GROUP_GET:
00282                         *result = tsp_get_group_size(buf[0]);
00283                         break;
00284                 case SYS_ASSOC_SET:
00285                         eeprom_write_byte(&ee_assoc[buf[0]].obj, buf[1]);
00286                         eeprom_write_byte(&ee_assoc[buf[0]].method, buf[2]);
00287                         // FIXME
00288                         break;
00289                 case SYS_ASSOC_GET:
00290                         result[0] = eeprom_read_byte(&ee_assoc[buf[0]].obj);
00291                         result[1] = eeprom_read_byte(&ee_assoc[buf[0]].method);
00292                         // FIXME
00293                         break;
00294                 case SYS_GET_ERROR_STATS:
00295                         lnk_get_error_stats((struct lnk_err_t *)result);
00296                         break;
00297         }
00298 }
00299 
00309 static void call_method(uint8_t obj, uint8_t method, uint8_t *buf, uint8_t len, uint8_t session)
00310 {
00311         struct AppObject *app;
00312         appObjCallback_t *obj_method;
00313         param_desc_t *params;
00314         event_desc_t *event;
00315 
00316         // event or method?
00317         if ((method&0x80) != 0) {
00318                 event = (event_desc_t*)READ_WORD(events_table[obj]);
00319                 // event written?
00320                 if ((session != 2) && (len == sizeof(event_desc_t))) {
00321                         eeprom_write_block(&event[method&0x7f], buf, sizeof(event_desc_t));
00322                 }
00323                 // event read?
00324                 if (session) {
00325                         lock = 1;
00326                         buf_init(buffer_info, &buffer.data, sizeof(event_desc_t));
00327                         eeprom_read_block(&buffer.data, &event[method&0x7f], sizeof(event_desc_t));
00328                 }
00329         } else {
00330                 app = (struct AppObject*)READ_WORD(app_object_table[obj]);
00331                 params = (param_desc_t*)READ_WORD(app->method_sizes);
00332                 if (len != PRG_RDB(&params[method].in)) return;
00333                 
00334                 obj_method = (appObjCallback_t*)READ_WORD(app->Callback);
00335                 if (session) {
00336                         lock = 1;
00337                         buf_init(buffer_info, &buffer.data, PRG_RDB(&params[method].out));
00338                         obj_method(app, method, buf, buffer.data, session==2);
00339                 } else {
00340                         obj_method(app, method, buf, NULL, 0); 
00341                 }
00342         }
00343 }
00344 
00345 /********************************************************************************
00346  * functions called from transport layer
00347  */
00348 
00359 net_buf_t *tsp_ind(uint8_t *buf, uint8_t len, uint8_t session)
00360 {
00361         uint8_t obj, method, cnt, id;
00362         
00363         // can we fulfill request?
00364         if ((session) && (lock != 0)) return NULL;
00365         
00366         // examine object id
00367         if (buf[0] < 32) {
00368                 // direct object addressing
00369                 obj = buf[0];
00370                 method = buf[1];
00371                 call_method(obj, method, buf+2, len-2, session);
00372         } else {
00373                 // association, look up association table
00374                 len--;
00375                 cnt = 0;
00376                 do {
00377                         id = eeprom_read_byte(&ee_assoc[cnt].id);
00378                         if (id == buf[0]) {
00379                                 obj = eeprom_read_byte(&ee_assoc[cnt].obj);
00380                                 method = eeprom_read_byte(&ee_assoc[cnt].method);
00381                                 call_method(obj, method, buf+1, len, session);
00382                         }
00383                         cnt++;
00384                 } while ((cnt < APP_MAX_ASSOC) && (id <= buf[0]));
00385         }
00386         
00387         return &buffer_info;
00388 }
00389 
00396 void tsp_con(uint8_t *buf, uint8_t len)
00397 {
00398         uint8_t obj, event;
00399         struct AppObject *app;
00400         appObjCallback_t *obj_method;
00401 
00402         // get active event     
00403         obj = event_buffer[event_rd].obj;
00404         event = event_buffer[event_rd].event;
00405         
00406         // set data
00407         app = (struct AppObject*)READ_WORD(app_object_table[obj]);
00408         obj_method = (appObjCallback_t*)READ_WORD(app->Callback);
00409         obj_method(app, event|0x80, buf, NULL, 0);
00410 }
00411 
00417 void tsp_con_fin(uint8_t status)
00418 {
00419         lock = 0;
00420 }
00421 
00422 /********************************************************************************
00423  * Public functions
00424  */
00425 
00431 void app_init(void)
00432 {
00433         #ifndef APP_STATIC
00434         app_object_table[0] = &__sys_obj;
00435         #endif
00436 }
00437 
00446 void app_process(void)
00447 {
00448         struct AppObject *app;
00449         appObjCallback_t *obj_method;
00450         param_desc_t *params;
00451         event_desc_t *ed;
00452         uint8_t len, obj, event;
00453         enum tsp_service_e service;
00454 
00455         // can we send at all?
00456         if (!tsp_clear_to_send() || (lock != 0)) return;
00457         
00458         // process pending events
00459         if (event_rd != event_wr) {
00460                 // get event
00461                 obj = event_buffer[(event_rd+1)&(APP_MAX_EVENTS-1)].obj;
00462                 event = event_buffer[(event_rd+1)&(APP_MAX_EVENTS-1)].event;
00463                 
00464                 // prepare buffer
00465                 app = (struct AppObject*)READ_WORD(app_object_table[obj]);
00466                 params = (param_desc_t*)READ_WORD(app->event_sizes);
00467                 len = PRG_RDB(&params[event].out);
00468                 buf_init(buffer_info, &buffer.data, len);
00469                 
00470                 // get data
00471                 obj_method = (appObjCallback_t*)READ_WORD(app->Callback);
00472                 obj_method(app, event|0x80, NULL, buffer.data, 0);
00473                 
00474                 // add header, get destination info
00475                 ed = (event_desc_t*)READ_WORD(events_table[obj]);
00476                 eeprom_read_block(&dest, &ed[event].addr, sizeof(net_addr_t));
00477                 service = (enum tsp_service_e)eeprom_read_byte(&ed[event].service);
00478                 buf_prep_char(&buffer_info, eeprom_read_byte(&ed[event].assoc));
00479                 
00480                 // send...
00481                 switch (tsp_requ(&buffer_info, &dest, service)) {
00482                         case 1:
00483                                 lock = 1;
00484                         case -1: 
00485                                 event_rd = (event_rd+1)&(APP_MAX_EVENTS-1);
00486                         default:
00487                                 break;
00488                 }
00489         }
00490 }
00491 
00500 void app_trigger_event(uint8_t obj, uint8_t event)
00501 {
00502         event_wr = (event_wr+1)&(APP_MAX_EVENTS-1);
00503         event_buffer[event_wr].obj = obj;
00504         event_buffer[event_wr].event = event;
00505 }
00506 
00507 #ifndef APP_STATIC
00508 
00519 uint8_t app_register_obj(struct AppObject *obj, uint8_t events)
00520 {
00521         app_object_table[next_obj] = obj;
00522         events_table[next_obj] = next_eeprom_addr;
00523         (uint8_t*)next_eeprom_addr += events*sizeof(event_desc_t);
00524         return next_obj++;
00525 }
00526 
00527 #endif

Generated on Fri Oct 17 16:45:53 2003 for OpenHome by doxygen 1.3.3