Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

kernel/lnp.c

Go to the documentation of this file.
00001 
00006 /*
00007  *  The contents of this file are subject to the Mozilla Public License
00008  *  Version 1.0 (the "License"); you may not use this file except in
00009  *  compliance with the License. You may obtain a copy of the License at
00010  *  http://www.mozilla.org/MPL/
00011  *
00012  *  Software distributed under the License is distributed on an "AS IS"
00013  *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
00014  *  License for the specific language governing rights and limitations
00015  *  under the License.
00016  *
00017  *  The Original Code is legOS code, released October 17, 1999.
00018  *
00019  *  The Initial Developer of the Original Code is Markus L. Noga.
00020  *  Portions created by Markus L. Noga are Copyright (C) 1999
00021  *  Markus L. Noga. All Rights Reserved.
00022  *
00023  *  Contributor(s): Markus L. Noga <markus@noga.de>
00024  */
00025 
00026 /*
00027  *  2000.05.01 - Paolo Masetti <paolo.masetti@itlug.org>
00028  *
00029  *  - IR lcd now reflect IR mode (near/far)
00030  *
00031  *  2001.09.10 - Zhengrong Zang <mikezang@iname.com>
00032  *
00033  *  - Remote control buttons
00034  *  - Standard firmware async message
00035  *
00036  *  2002.04.23 - Ted Hess <thess@kitschensync.net>
00037  *
00038  *  - Integrate Ross Crawford/Zhengrong Zang remote control message parser
00039  *    and RCX op-code dispatcher
00040  *
00041  */
00042 
00043 #include <sys/lnp.h>
00044 
00045 #ifdef CONF_LNP
00046 
00047 #include <sys/lnp-logical.h>
00048 #include <sys/irq.h>
00049 #include <stdlib.h>
00050 
00051 #ifdef CONF_VIS
00052 #include <dlcd.h>
00053 #include <sys/lcd.h>
00054 #endif
00055 
00056 #ifdef CONF_AUTOSHUTOFF
00057 #include <sys/timeout.h>
00058 #endif
00059 
00060 #include <string.h>
00061 
00063 //
00064 // Variables
00065 //
00067 
00070 unsigned char lnp_hostaddr = (CONF_LNP_HOSTADDR << 4) & CONF_LNP_HOSTMASK;
00071 
00073 volatile unsigned short lnp_timeout_counter;
00074 
00076 unsigned short lnp_timeout=LNP_BYTE_TIMEOUT;
00077 
00079 lnp_integrity_state_t lnp_integrity_state;
00080 
00082 
00084 volatile lnp_integrity_handler_t lnp_integrity_handler;
00085 
00087 
00090 volatile lnp_addressing_handler_t lnp_addressing_handler[LNP_PORTMASK+1];
00091 
00092 #if !defined(CONF_MM)
00093 static char lnp_buffer[260];
00094 #endif // CONF_MM
00095 
00096 #if defined(CONF_RCX_PROTOCOL)
00097 
00098 lnp_remote_handler_t lnp_remote_handler;
00099 
00101 const unsigned char lnp_rcx_header[LNP_RCX_HEADER_LENGTH] = {0xff,0x00};
00102 
00104 const unsigned char lnp_rcx_remote_op[LNP_RCX_REMOTE_OP_LENGTH] = {0xd2,0x2d};
00105 
00106 
00108 unsigned char lnp_rcx_temp0;
00109 unsigned char lnp_rcx_temp1;
00110 
00112 unsigned char lnp_rcx_checksum;
00113 
00114 #endif
00115 
00116 #if defined(CONF_RCX_MESSAGE)
00117 
00118 const unsigned char lnp_rcx_msg_op[LNP_RCX_MSG_OP_LENGTH] = {0xf7,0x08};
00119 
00121 unsigned char lnp_rcx_message;
00122 
00123 #endif
00124 
00126 //
00127 // Functions
00128 //
00130 
00131 #define lnp_checksum_init(sum)  (unsigned char)((sum) = 0xff)
00132 #define lnp_checksum_step(sum,d)  (unsigned char)((sum) += (d))
00133 
00134 #ifdef CONF_HOST
00135 unsigned char lnp_checksum_copy( unsigned char *dest,
00136                                  const unsigned char *data, 
00137                                  unsigned length )
00138 {
00139   unsigned char a = 0xff;
00140   unsigned char t;
00141 
00142   do {
00143     t = *data++;
00144     a += t;
00145     *dest++ = t;
00146     length--;
00147   } while (length > 0);
00148 
00149   return a;
00150 }
00151 #else
00152 __asm__(
00153         ".text\n"
00154         "_lnp_checksum_copy:\n"
00155         ";; r0: dest, r1: data, r2: length;\n"
00156         
00157         "    add.w r0,r2         ; r2: end \n"
00158         "    mov.b #0xff,r3l     ; r3l: a  \n"
00159         
00160         "0:\n"
00161         "    mov.b @r1+,r3h      ; r3h = *data++ \n"
00162         "    add.b r3h,r3l       ; a += r3h      \n"
00163         "    mov.b r3h,@r0       ; *dest++ = r3h \n"
00164         "    adds  #1,r0 \n"
00165         "    cmp.w r0,r2 \n"
00166         "    bne   0b \n"
00167         
00168         "    sub.w r0,r0 \n"
00169         "    mov.b r3l,r0l \n"
00170         "    rts \n"
00171         );
00172 #endif
00173 
00175 
00177 int lnp_integrity_write(const unsigned char *data,unsigned char length) {
00178   int r;
00179 #if defined(CONF_MM)
00180   char* buffer_ptr = malloc(length+3);
00181 #else // CONF_MM
00182   char* buffer_ptr = lnp_buffer;
00183 #endif // CONF_MM
00184   unsigned char c = lnp_checksum_copy( buffer_ptr+2, data, length);
00185   lnp_checksum_step( c, buffer_ptr[0]=0xf0 );
00186   lnp_checksum_step( c, buffer_ptr[1]=length );
00187   buffer_ptr[length+2] = c;
00188   r = lnp_logical_write(buffer_ptr,length+3);
00189 #if defined(CONF_MM)
00190   free(buffer_ptr); 
00191 #endif // CONF_MM
00192   return r;
00193 }
00194 
00196 
00198 int lnp_addressing_write(const unsigned char *data,unsigned char length,
00199                          unsigned char dest,unsigned char srcport) {
00200   int r;
00201 #if defined(CONF_MM)
00202   char* buffer_ptr = malloc(length+5);
00203 #else // CONF_MM
00204   char* buffer_ptr = lnp_buffer;
00205 #endif // CONF_MM
00206   unsigned char c = lnp_checksum_copy( buffer_ptr+4, data, length );
00207   lnp_checksum_step( c, buffer_ptr[0]=0xf1 );
00208   lnp_checksum_step( c, buffer_ptr[1]=length+2 );
00209   lnp_checksum_step( c, buffer_ptr[2]=dest );
00210   lnp_checksum_step( c, buffer_ptr[3]=
00211                    (lnp_hostaddr | (srcport & LNP_PORTMASK)) );
00212   buffer_ptr[length+4] = c;
00213   r = lnp_logical_write(buffer_ptr,length+5);
00214 #if defined(CONF_MM)
00215   free(buffer_ptr); 
00216 #endif // CONF_MM
00217   return r;
00218 }
00219 
00221 void lnp_receive_packet(const unsigned char *data) {
00222   unsigned char header=*(data++);
00223   unsigned char length=*(data++);
00224   lnp_integrity_handler_t intgh;
00225   lnp_addressing_handler_t addrh;
00226 
00227   // only handle non-degenerate packets in boot protocol 0xf0
00228   //
00229   switch(header) {
00230     case 0xf0:        // raw integrity layer packet, no addressing.
00231       intgh = lnp_integrity_handler;
00232       if(intgh) {
00233 #ifdef CONF_AUTOSHUTOFF
00234         shutoff_restart();
00235 #endif
00236         intgh(data,length);
00237       }
00238       break;
00239 
00240     case 0xf1:        // addressing layer.
00241       if(length>2) {
00242         unsigned char dest=*(data++);
00243 
00244         if(lnp_hostaddr == (dest & LNP_HOSTMASK)) {
00245           unsigned char port=dest & LNP_PORTMASK;
00246           addrh = lnp_addressing_handler[port];
00247           if(addrh) {
00248             unsigned char src=*(data++);
00249 #ifdef CONF_AUTOSHUTOFF
00250             shutoff_restart();
00251 #endif
00252             addrh(data,length-2,src);
00253           }
00254         }
00255       }
00256 
00257   } // switch(header)
00258 }
00259 
00261 void lnp_integrity_byte(unsigned char b) {
00262   static unsigned char buffer[256+3];
00263   static int bytesRead,endOfData;
00264   static unsigned char chk;
00265 
00266   if(lnp_integrity_state==LNPwaitHeader)
00267     bytesRead=0;
00268 
00269   buffer[bytesRead++]=b;
00270 
00271   switch(lnp_integrity_state) {
00272     case LNPwaitHeader:
00273       // valid headers are 0xf0 .. 0xf7
00274       //
00275       if(((b & 0xf8) == 0xf0) || (b == 0x55)) {
00276 #ifdef CONF_VIS
00277         if (lnp_logical_range_is_far()) {
00278           dlcd_show(LCD_IR_UPPER);
00279           dlcd_show(LCD_IR_LOWER);
00280         } else {
00281           dlcd_hide(LCD_IR_UPPER);
00282           dlcd_show(LCD_IR_LOWER);
00283         }
00284 #ifndef CONF_LCD_REFRESH
00285         lcd_refresh();
00286 #endif
00287 #endif
00288         // Init checksum
00289         lnp_checksum_init( chk );
00290     
00291         // switch on protocol header
00292         if (b == 0x55) {
00293 #if defined(CONF_RCX_PROTOCOL) || defined(CONF_RCX_MESSAGE)
00294           // 0x55 is header for standard firmware message
00295           lnp_integrity_state = LNPwaitRMH1;
00296 #else
00297           lnp_integrity_reset();
00298 #endif
00299         } else {
00300           lnp_integrity_state++;
00301         }
00302       }
00303       break;
00304 
00305     case LNPwaitLength:
00306       endOfData=b+2;
00307       lnp_integrity_state++;
00308       break;
00309 
00310     case LNPwaitData:
00311       if(bytesRead==endOfData)
00312   lnp_integrity_state++;
00313       break;
00314 
00315     case LNPwaitCRC:
00316       if(b==chk)
00317   lnp_receive_packet(buffer);
00318       lnp_integrity_reset();
00319     break;
00320 
00321 #if defined(CONF_RCX_PROTOCOL) || defined (CONF_RCX_MESSAGE)
00322   // state machine to handle remote
00323     case LNPwaitRMH1:
00324     case LNPwaitRMH2:
00325       // waiting for header bytes
00326       if ( b == lnp_rcx_header[ lnp_integrity_state-LNPwaitRMH1 ] )
00327         lnp_integrity_state++;
00328       else
00329         lnp_integrity_reset();
00330       break;
00331 
00332     case LNPwaitRMH3:
00333     case LNPwaitRMH4:
00334       if ( b == lnp_rcx_remote_op[ lnp_integrity_state-LNPwaitRMH3 ] )
00335         lnp_integrity_state++;
00336 #if defined(CONF_RCX_MESSAGE)
00337       else if ( b == lnp_rcx_msg_op[ lnp_integrity_state-LNPwaitRMH3 ] )
00338         lnp_integrity_state = LNPwaitMH4;
00339 #endif
00340       else
00341         lnp_integrity_reset();
00342       break;
00343 
00344     case LNPwaitRB0:
00345       lnp_rcx_temp0 = b;
00346       lnp_integrity_state++;
00347       break;
00348 
00349     case LNPwaitRB0I:
00350       if ( (unsigned char)~b == lnp_rcx_temp0 )
00351         lnp_integrity_state++;
00352       else
00353         lnp_integrity_reset();
00354       break;
00355 
00356     case LNPwaitRB1:
00357       lnp_rcx_temp1 = b;
00358       lnp_integrity_state++;
00359       break;
00360 
00361     case LNPwaitRB1I:
00362       if ( (unsigned char)~b == lnp_rcx_temp1 )
00363         lnp_integrity_state++;
00364       else
00365         lnp_integrity_reset();
00366       break;
00367 
00368     case LNPwaitRC:
00369       lnp_rcx_checksum = 0xd2 + lnp_rcx_temp0 + lnp_rcx_temp1;
00370       if ( b == lnp_rcx_checksum )
00371         lnp_integrity_state++;
00372       else
00373         lnp_integrity_reset();
00374       break;
00375 
00376     case LNPwaitRCI:
00377       // if checksum valid and remote handler has been installed, call remote handler
00378     if ( b == (unsigned char)~lnp_rcx_checksum) {
00379 #if defined(CONF_RCX_MESSAGE)
00380      // if a message, set message number and exit
00381      if (lnp_rcx_temp1 & 0x07)
00382      {
00383         lnp_rcx_message = (lnp_rcx_temp1 > 2) ? 3 : lnp_rcx_temp1;
00384      } 
00385      else
00386 #endif
00387      {
00388         // Invoke remote handler if any
00389         lnp_remote_handler_t rmth = lnp_remote_handler;
00390         if (rmth)
00391           rmth( (lnp_rcx_temp0<<8)+lnp_rcx_temp1 );
00392         }
00393       }
00394       // reset state machine when done
00395       lnp_integrity_reset();
00396       break;
00397 #endif
00398 
00399 #if defined(CONF_RCX_MESSAGE)
00400     // state machine to handle RCX protocol messages
00401     case LNPwaitMH3:
00402     case LNPwaitMH4:
00403       if ( b == lnp_rcx_msg_op[ lnp_integrity_state-LNPwaitMH3 ] )
00404         lnp_integrity_state++;
00405       else
00406         lnp_integrity_reset();
00407       break;
00408 
00409     case LNPwaitMN:
00410       lnp_rcx_temp0 = b;
00411       lnp_integrity_state++;
00412       break;
00413 
00414     case LNPwaitMNC:
00415       if ( (unsigned char)~b == lnp_rcx_temp0 )
00416         lnp_integrity_state++;
00417       else
00418         lnp_integrity_reset();
00419       break;
00420 
00421     case LNPwaitMC:
00422       lnp_rcx_temp1 = 0xf7 + lnp_rcx_temp0;
00423 
00424       if (b == lnp_rcx_temp1)
00425          lnp_integrity_state++;
00426       else
00427         lnp_integrity_reset();
00428       break;
00429 
00430     case LNPwaitMCC:
00431       // set message variable if it is valid message
00432       if ( (unsigned char)~b == lnp_rcx_temp1 )
00433         lnp_rcx_message = lnp_rcx_temp0;
00434       // reset state machine
00435       lnp_integrity_reset();
00436       break;
00437 #endif
00438   }
00439   // Accumulate checksum
00440   lnp_checksum_step( chk, b );
00441 }
00442 
00444 #if defined(CONF_RCX_COMPILER) || defined(CONF_HOST)
00445 void lnp_integrity_reset(void) {
00446 #else
00447 HANDLER_WRAPPER("lnp_integrity_reset","lnp_integrity_reset_core");
00448 void lnp_integrity_reset_core(void) {
00449 #endif
00450 #ifndef CONF_HOST
00451   if(tx_state>TX_IDLE) {
00452     txend_handler();
00453     tx_state=TX_COLL;
00454   } else
00455 #endif
00456   if(lnp_integrity_state!=LNPwaitHeader) {
00457     lnp_integrity_state=LNPwaitHeader;
00458 
00459 #ifdef CONF_VIS
00460     dlcd_hide(LCD_IR_LOWER);
00461     dlcd_hide(LCD_IR_UPPER);
00462 #ifndef CONF_LCD_REFRESH
00463     lcd_refresh();
00464 #endif
00465 #endif
00466   }
00467 }
00468 
00470 
00472 int lnp_integrity_active(void) {
00473   return lnp_integrity_state!=LNPwaitHeader;
00474 }
00475 
00477 #if defined(CONF_RCX_COMPILER) || defined(CONF_HOST)
00478 void lnp_timeout_reset(void) {
00479 #else
00480 HANDLER_WRAPPER("lnp_timeout_reset","lnp_timeout_reset_core");
00481 void lnp_timeout_reset_core(void) {
00482 #endif
00483   lnp_timeout_counter=lnp_timeout;
00484 }
00485 
00487 
00489 void lnp_timeout_set(unsigned short timeout) {
00490   lnp_timeout_counter=lnp_timeout=timeout;
00491 }
00492 
00494 
00496 void lnp_init(void) {
00497   int k;
00498   
00499   for(k=1; k<=LNP_PORTMASK; k++)
00500     lnp_addressing_handler[k]=LNP_DUMMY_ADDRESSING;
00501   lnp_integrity_handler=LNP_DUMMY_INTEGRITY;
00502 
00503 #if defined(CONF_RCX_PROTOCOL)
00504   lnp_remote_handler=LNP_DUMMY_REMOTE;
00505 #endif
00506 #if defined(CONF_RCX_MESSAGE)
00507   clear_msg();
00508 #endif
00509 }
00510 
00511 #ifdef CONF_RCX_MESSAGE
00512 wakeup_t msg_received(wakeup_t m) {
00513     return (m == 0 ? lnp_rcx_message != 0 : lnp_rcx_message == m);
00514 }
00515 
00517 
00519 int send_msg(unsigned char msg)
00520 {
00521   int r;
00522 #if defined(CONF_MM)
00523   char* buffer_ptr = malloc(9);
00524 #else // CONF_MM
00525   char* buffer_ptr = lnp_buffer;
00526 #endif // CONF_MM
00527   buffer_ptr[0]=0x55;
00528   buffer_ptr[1]=0xff;
00529   buffer_ptr[2]=0x00;
00530   buffer_ptr[3]=0xf7;
00531   buffer_ptr[4]=0x08;
00532   buffer_ptr[5]=msg;
00533   buffer_ptr[6]=(unsigned char) (0xff-msg);
00534   buffer_ptr[7]=(unsigned char) (0xf7+msg);
00535   buffer_ptr[8]=(unsigned char) (0x08-msg);
00536   r = lnp_logical_write(buffer_ptr,9);
00537 #if defined(CONF_MM)
00538   free(buffer_ptr); 
00539 #endif // CONF_MM
00540   return r;
00541 }
00542 #endif
00543 
00544 #endif // CONF_LNP

brickOS is released under the Mozilla Public License.
Original code copyright 1998-2002 by the authors.

Generated on Mon Feb 16 21:02:10 2004 for brickOS Kernel Developer by doxygen 1.3.5