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. |