lnp.c
Go to the documentation of this file.
1 
6 /*
7  * The contents of this file are subject to the Mozilla Public License
8  * Version 1.0 (the "License"); you may not use this file except in
9  * compliance with the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS"
13  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
14  * License for the specific language governing rights and limitations
15  * under the License.
16  *
17  * The Original Code is legOS code, released October 17, 1999.
18  *
19  * The Initial Developer of the Original Code is Markus L. Noga.
20  * Portions created by Markus L. Noga are Copyright (C) 1999
21  * Markus L. Noga. All Rights Reserved.
22  *
23  * Contributor(s): Markus L. Noga <markus@noga.de>
24  */
25 
26 /*
27  * 2000.05.01 - Paolo Masetti <paolo.masetti@itlug.org>
28  *
29  * - IR lcd now reflect IR mode (near/far)
30  *
31  * 2001.09.10 - Zhengrong Zang <mikezang@iname.com>
32  *
33  * - Remote control buttons
34  * - Standard firmware async message
35  *
36  * 2002.04.23 - Ted Hess <thess@kitschensync.net>
37  *
38  * - Integrate Ross Crawford/Zhengrong Zang remote control message parser
39  * and RCX op-code dispatcher
40  *
41  */
42 
43 #include <sys/lnp.h>
44 
45 #ifdef CONF_LNP
46 
47 #include <sys/lnp-logical.h>
48 #include <sys/irq.h>
49 #include <stdlib.h>
50 
51 #ifdef CONF_VIS
52 #include <dlcd.h>
53 #include <sys/lcd.h>
54 #endif
55 
56 #ifdef CONF_AUTOSHUTOFF
57 #include <sys/timeout.h>
58 #endif
59 
60 #include <string.h>
61 
63 //
64 // Variables
65 //
67 
70 unsigned char lnp_hostaddr = (CONF_LNP_HOSTADDR << 4) & CONF_LNP_HOSTMASK;
71 
73 volatile unsigned short lnp_timeout_counter;
74 
76 unsigned short lnp_timeout=LNP_BYTE_TIMEOUT;
77 
80 
82 
85 
87 
91 
92 #if !defined(CONF_MM)
93 static char lnp_buffer[260];
94 #endif // CONF_MM
95 
96 #if defined(CONF_RCX_PROTOCOL)
99 
101 const unsigned char lnp_rcx_header[LNP_RCX_HEADER_LENGTH] = {0xff,0x00};
102 
104 const unsigned char lnp_rcx_remote_op[LNP_RCX_REMOTE_OP_LENGTH] = {0xd2,0x2d};
105 
106 
108 unsigned char lnp_rcx_temp0;
109 unsigned char lnp_rcx_temp1;
110 
112 unsigned char lnp_rcx_checksum;
113 
114 #endif
115 
116 #if defined(CONF_RCX_MESSAGE)
117 const unsigned char lnp_rcx_msg_op[LNP_RCX_MSG_OP_LENGTH] = {0xf7,0x08};
119 
121 unsigned char lnp_rcx_message;
122 
123 #endif
124 
126 //
127 // Functions
128 //
130 
131 #define lnp_checksum_init(sum) (unsigned char)((sum) = 0xff)
132 #define lnp_checksum_step(sum,d) (unsigned char)((sum) += (d))
133 
134 #ifdef CONF_HOST
135 unsigned char lnp_checksum_copy( unsigned char *dest,
136  const unsigned char *data,
137  unsigned length )
138 {
139  unsigned char a = 0xff;
140  unsigned char t;
141 
142  do {
143  t = *data++;
144  a += t;
145  *dest++ = t;
146  length--;
147  } while (length > 0);
148 
149  return a;
150 }
151 #else
152 __asm__(
153  ".text\n"
154  "_lnp_checksum_copy:\n"
155  ";; r0: dest, r1: data, r2: length;\n"
156 
157  " add.w r0,r2 ; r2: end \n"
158  " mov.b #0xff,r3l ; r3l: a \n"
159 
160  "0:\n"
161  " mov.b @r1+,r3h ; r3h = *data++ \n"
162  " add.b r3h,r3l ; a += r3h \n"
163  " mov.b r3h,@r0 ; *dest++ = r3h \n"
164  " adds #1,r0 \n"
165  " cmp.w r0,r2 \n"
166  " bne 0b \n"
167 
168  " sub.w r0,r0 \n"
169  " mov.b r3l,r0l \n"
170  " rts \n"
171  );
172 #endif
173 
175 
177 int lnp_integrity_write(const unsigned char *data,unsigned char length) {
178  int r;
179 #if defined(CONF_MM)
180  char* buffer_ptr = malloc(length+3);
181 #else // CONF_MM
182  char* buffer_ptr = lnp_buffer;
183 #endif // CONF_MM
184  unsigned char c = lnp_checksum_copy( buffer_ptr+2, data, length);
185  lnp_checksum_step( c, buffer_ptr[0]=0xf0 );
186  lnp_checksum_step( c, buffer_ptr[1]=length );
187  buffer_ptr[length+2] = c;
188  r = lnp_logical_write(buffer_ptr,length+3);
189 #if defined(CONF_MM)
190  free(buffer_ptr);
191 #endif // CONF_MM
192  return r;
193 }
194 
196 
198 int lnp_addressing_write(const unsigned char *data,unsigned char length,
199  unsigned char dest,unsigned char srcport) {
200  int r;
201 #if defined(CONF_MM)
202  char* buffer_ptr = malloc(length+5);
203 #else // CONF_MM
204  char* buffer_ptr = lnp_buffer;
205 #endif // CONF_MM
206  unsigned char c = lnp_checksum_copy( buffer_ptr+4, data, length );
207  lnp_checksum_step( c, buffer_ptr[0]=0xf1 );
208  lnp_checksum_step( c, buffer_ptr[1]=length+2 );
209  lnp_checksum_step( c, buffer_ptr[2]=dest );
210  lnp_checksum_step( c, buffer_ptr[3]=
211  (lnp_hostaddr | (srcport & LNP_PORTMASK)) );
212  buffer_ptr[length+4] = c;
213  r = lnp_logical_write(buffer_ptr,length+5);
214 #if defined(CONF_MM)
215  free(buffer_ptr);
216 #endif // CONF_MM
217  return r;
218 }
219 
221 void lnp_receive_packet(const unsigned char *data) {
222  unsigned char header=*(data++);
223  unsigned char length=*(data++);
226 
227  // only handle non-degenerate packets in boot protocol 0xf0
228  //
229  switch(header) {
230  case 0xf0: // raw integrity layer packet, no addressing.
231  intgh = lnp_integrity_handler;
232  if(intgh) {
233 #ifdef CONF_AUTOSHUTOFF
234  shutoff_restart();
235 #endif
236  intgh(data,length);
237  }
238  break;
239 
240  case 0xf1: // addressing layer.
241  if(length>2) {
242  unsigned char dest=*(data++);
243 
244  if(lnp_hostaddr == (dest & LNP_HOSTMASK)) {
245  unsigned char port=dest & LNP_PORTMASK;
246  addrh = lnp_addressing_handler[port];
247  if(addrh) {
248  unsigned char src=*(data++);
249 #ifdef CONF_AUTOSHUTOFF
250  shutoff_restart();
251 #endif
252  addrh(data,length-2,src);
253  }
254  }
255  }
256 
257  } // switch(header)
258 }
259 
261 void lnp_integrity_byte(unsigned char b) {
262  static unsigned char buffer[256+3];
263  static int bytesRead,endOfData;
264  static unsigned char chk;
265 
267  bytesRead=0;
268 
269  buffer[bytesRead++]=b;
270 
271  switch(lnp_integrity_state) {
272  case LNPwaitHeader:
273  // valid headers are 0xf0 .. 0xf7
274  //
275  if(((b & 0xf8) == 0xf0) || (b == 0x55)) {
276 #ifdef CONF_VIS
277  if (lnp_logical_range_is_far()) {
280  } else {
283  }
284 #ifndef CONF_LCD_REFRESH
285  lcd_refresh();
286 #endif
287 #endif
288  // Init checksum
289  lnp_checksum_init( chk );
290 
291  // switch on protocol header
292  if (b == 0x55) {
293 #if defined(CONF_RCX_PROTOCOL) || defined(CONF_RCX_MESSAGE)
294  // 0x55 is header for standard firmware message
296 #else
298 #endif
299  } else {
301  }
302  }
303  break;
304 
305  case LNPwaitLength:
306  endOfData=b+2;
308  break;
309 
310  case LNPwaitData:
311  if(bytesRead==endOfData)
313  break;
314 
315  case LNPwaitCRC:
316  if(b==chk)
317  lnp_receive_packet(buffer);
319  break;
320 
321 #if defined(CONF_RCX_PROTOCOL) || defined (CONF_RCX_MESSAGE)
322  // state machine to handle remote
323  case LNPwaitRMH1:
324  case LNPwaitRMH2:
325  // waiting for header bytes
326  if ( b == lnp_rcx_header[ lnp_integrity_state-LNPwaitRMH1 ] )
328  else
330  break;
331 
332  case LNPwaitRMH3:
333  case LNPwaitRMH4:
334  if ( b == lnp_rcx_remote_op[ lnp_integrity_state-LNPwaitRMH3 ] )
336 #if defined(CONF_RCX_MESSAGE)
337  else if ( b == lnp_rcx_msg_op[ lnp_integrity_state-LNPwaitRMH3 ] )
339 #endif
340  else
342  break;
343 
344  case LNPwaitRB0:
345  lnp_rcx_temp0 = b;
347  break;
348 
349  case LNPwaitRB0I:
350  if ( (unsigned char)~b == lnp_rcx_temp0 )
352  else
354  break;
355 
356  case LNPwaitRB1:
357  lnp_rcx_temp1 = b;
359  break;
360 
361  case LNPwaitRB1I:
362  if ( (unsigned char)~b == lnp_rcx_temp1 )
364  else
366  break;
367 
368  case LNPwaitRC:
369  lnp_rcx_checksum = 0xd2 + lnp_rcx_temp0 + lnp_rcx_temp1;
370  if ( b == lnp_rcx_checksum )
372  else
374  break;
375 
376  case LNPwaitRCI:
377  // if checksum valid and remote handler has been installed, call remote handler
378  if ( b == (unsigned char)~lnp_rcx_checksum) {
379 #if defined(CONF_RCX_MESSAGE)
380  // if a message, set message number and exit
381  if (lnp_rcx_temp1 & 0x07)
382  {
383  lnp_rcx_message = (lnp_rcx_temp1 > 2) ? 3 : lnp_rcx_temp1;
384  }
385  else
386 #endif
387  {
388  // Invoke remote handler if any
390  if (rmth)
391  rmth( (lnp_rcx_temp0<<8)+lnp_rcx_temp1 );
392  }
393  }
394  // reset state machine when done
396  break;
397 #endif
398 
399 #if defined(CONF_RCX_MESSAGE)
400  // state machine to handle RCX protocol messages
401  case LNPwaitMH3:
402  case LNPwaitMH4:
403  if ( b == lnp_rcx_msg_op[ lnp_integrity_state-LNPwaitMH3 ] )
405  else
407  break;
408 
409  case LNPwaitMN:
410  lnp_rcx_temp0 = b;
412  break;
413 
414  case LNPwaitMNC:
415  if ( (unsigned char)~b == lnp_rcx_temp0 )
417  else
419  break;
420 
421  case LNPwaitMC:
422  lnp_rcx_temp1 = 0xf7 + lnp_rcx_temp0;
423 
424  if (b == lnp_rcx_temp1)
426  else
428  break;
429 
430  case LNPwaitMCC:
431  // set message variable if it is valid message
432  if ( (unsigned char)~b == lnp_rcx_temp1 )
433  lnp_rcx_message = lnp_rcx_temp0;
434  // reset state machine
436  break;
437 #endif
438  }
439  // Accumulate checksum
440  lnp_checksum_step( chk, b );
441 }
442 
444 #if defined(CONF_RCX_COMPILER) || defined(CONF_HOST)
445 void lnp_integrity_reset(void) {
446 #else
447 HANDLER_WRAPPER("lnp_integrity_reset","lnp_integrity_reset_core");
448 void lnp_integrity_reset_core(void) {
449 #endif
450 #ifndef CONF_HOST
451  if(tx_state>TX_IDLE) {
452  txend_handler();
454  } else
455 #endif
458 
459 #ifdef CONF_VIS
462 #ifndef CONF_LCD_REFRESH
463  lcd_refresh();
464 #endif
465 #endif
466  }
467 }
468 
470 
472 int lnp_integrity_active(void) {
474 }
475 
477 #if defined(CONF_RCX_COMPILER) || defined(CONF_HOST)
478 void lnp_timeout_reset(void) {
479 #else
480 HANDLER_WRAPPER("lnp_timeout_reset","lnp_timeout_reset_core");
481 void lnp_timeout_reset_core(void) {
482 #endif
484 }
485 
487 
489 void lnp_timeout_set(unsigned short timeout) {
491 }
492 
494 
496 void lnp_init(void) {
497  int k;
498 
499  for(k=1; k<=LNP_PORTMASK; k++)
502 
503 #if defined(CONF_RCX_PROTOCOL)
505 #endif
506 #if defined(CONF_RCX_MESSAGE)
507  clear_msg();
508 #endif
509 }
510 
511 #ifdef CONF_RCX_MESSAGE
513  return (m == 0 ? lnp_rcx_message != 0 : lnp_rcx_message == m);
514 }
515 
517 
519 int send_msg(unsigned char msg)
520 {
521  int r;
522 #if defined(CONF_MM)
523  char* buffer_ptr = malloc(9);
524 #else // CONF_MM
525  char* buffer_ptr = lnp_buffer;
526 #endif // CONF_MM
527  buffer_ptr[0]=0x55;
528  buffer_ptr[1]=0xff;
529  buffer_ptr[2]=0x00;
530  buffer_ptr[3]=0xf7;
531  buffer_ptr[4]=0x08;
532  buffer_ptr[5]=msg;
533  buffer_ptr[6]=(unsigned char) (0xff-msg);
534  buffer_ptr[7]=(unsigned char) (0xf7+msg);
535  buffer_ptr[8]=(unsigned char) (0x08-msg);
536  r = lnp_logical_write(buffer_ptr,9);
537 #if defined(CONF_MM)
538  free(buffer_ptr);
539 #endif // CONF_MM
540  return r;
541 }
542 #endif
543 
544 #endif // CONF_LNP
lnp_remote_handler_t
void(* lnp_remote_handler_t)(unsigned int)
handler for remote
Definition: lnp.h:67
lnp_timeout_counter
volatile unsigned short lnp_timeout_counter
the timeout counter in ms
clear_msg
void clear_msg(void)
clear last message from standard firmware
Definition: lnp.h:136
lcd_refresh
void lcd_refresh(void)
refresh the entire LCD display
Definition: lcd.c:254
LNPwaitRMH1
states when waiting for rcx protocol message
Definition: lnp.h:68
lnp_integrity_reset
void lnp_integrity_reset(void)
reset the integrity layer on error or timeout.
shutoff_restart
void shutoff_restart(void)
send_msg
int send_msg(unsigned char msg)
send a standard firmware message
txend_handler
void txend_handler(void)
Callback: end of transmission.
LNPwaitRB0
states when waiting for remote buttons args
Definition: lnp.h:77
lnp_hostaddr
unsigned char lnp_hostaddr
LNP host address.
lnp_integrity_active
int lnp_integrity_active(void)
return whether a packet is currently being received
Definition: lnp.h:140
tx_state
volatile signed char tx_state
transmit status
string.h
Interface: string functions.
lnp_remote_handler
lnp_remote_handler_t lnp_remote_handler
packets from remote have no ports
timeout.h
Internal Interface: Powerdown Timer Routines.
LNPwaitRB1I
Definition: lnp.h:80
HANDLER_WRAPPER
HANDLER_WRAPPER("lcd_refresh_next_byte", "lcd_refresh_next_byte_core")
lcd refresh handler, called from system timer interrupt
LNP_DUMMY_REMOTE
#define LNP_DUMMY_REMOTE
dummy remote packet handler
Definition: lnp.h:70
LNP_RCX_HEADER_LENGTH
#define LNP_RCX_HEADER_LENGTH
length of header from remote/rcx, -1 because first byte is used to id sequence
Definition: lnp.h:50
LNPwaitRC
Definition: lnp.h:81
lnp_timeout
unsigned short lnp_timeout
the timeout length in ms
LNPwaitRCI
Definition: lnp.h:82
lnp_integrity_handler_t
void(* lnp_integrity_handler_t)(const unsigned char *, unsigned char)
the integrity layer packet handler type
Definition: lnp.h:50
free
void free(void *ptr)
return the allocated memory to memory management.
malloc
void * malloc(size_t size)
allocate and return pointer to uninitialized memory
lnp_integrity_state
lnp_integrity_state_t lnp_integrity_state
the integrity layer state
wakeup_t
unsigned long wakeup_t
wakeup data area type
Definition: tm.h:57
LNPwaitData
Definition: lnp.h:63
lnp_integrity_write
int lnp_integrity_write(const unsigned char *data, unsigned char length)
send a LNP integrity layer packet of given length
lnp_timeout_set
void lnp_timeout_set(unsigned short timeout)
set the inter-byte timeout and reset the timeout counter to that value.
Definition: lnp.h:155
LNP_HOSTMASK
#define LNP_HOSTMASK
the LNP host mask (config.h)
Definition: lnp.h:43
LNP_RCX_REMOTE_OP_LENGTH
#define LNP_RCX_REMOTE_OP_LENGTH
length of remote button op, -3 because first 3 bytes is used to id sequence
Definition: lnp.h:53
LNPwaitMC
Definition: lnp.h:91
lnp_rcx_message
unsigned char lnp_rcx_message
message variable
LNPwaitRB0I
Definition: lnp.h:78
lnp.h
Internal LNP Interface: link networking protocol.
lnp_integrity_handler
volatile lnp_integrity_handler_t lnp_integrity_handler
there are no ports for integrity layer packets, so there's just
dlcd_show
#define dlcd_show(a)
set a segment directly in the LCD buffer
Definition: dlcd.h:175
__asm__
__asm__("\n\ .text\n\ .globl _atomic_inc\n\ _atomic_inc:\n\ stc ccr, r1h ; save flags\n\ orc #0x80, ccr ; disable all but NMI\n\ mov.b @r0, r1l\n\ inc r1l\n\ mov.b r1l, @r0\n\ ldc r1h, ccr ; restore flags\n\ rts\n\ ")
CONF_LNP_HOSTMASK
#define CONF_LNP_HOSTMASK
LNP host mask.
Definition: config.h:58
TX_IDLE
#define TX_IDLE
not transmitting, last xmit OK
Definition: lnp-logical.h:67
msg_received
wakeup_t msg_received(wakeup_t m)
wait until receive a message
lnp_integrity_byte
void lnp_integrity_byte(unsigned char b)
receive a byte from the physical layer, decoding integrity layer packets.
LNPwaitMNC
Definition: lnp.h:90
TX_COLL
#define TX_COLL
not transmitting, last xmit was collision
Definition: lnp-logical.h:66
lcd.h
Internal Interface: LCD control and constants.
lnp_logical_range_is_far
int lnp_logical_range_is_far(void)
Test the IR transmitter range setting.
Definition: lnp-logical.h:73
LNPwaitRMH4
Definition: lnp.h:71
LCD_IR_LOWER
#define LCD_IR_LOWER
Definition: dlcd.h:154
lnp_checksum_copy
unsigned char lnp_checksum_copy(unsigned char *dest, const unsigned char *data, unsigned length)
the LNP ‘copy and compute checksum’ function.
LNP_PORTMASK
#define LNP_PORTMASK
LNP port mask is derived from host mask.
Definition: lnp.h:46
CONF_LNP_HOSTADDR
#define CONF_LNP_HOSTADDR
LNP host address.
Definition: config.h:54
LNP_DUMMY_INTEGRITY
#define LNP_DUMMY_INTEGRITY
dummy integrity layer packet handler
Definition: lnp.h:58
lnp_addressing_write
int lnp_addressing_write(const unsigned char *data, unsigned char length, unsigned char dest, unsigned char srcport)
send a LNP addressing layer packet of given length
LNP_DUMMY_ADDRESSING
#define LNP_DUMMY_ADDRESSING
dummy addressing layer packet handler
Definition: lnp.h:61
irq.h
Internal LNP Interface: RCX redirected IRQ vectors.
LNPwaitLength
Definition: lnp.h:62
LNPwaitRB1
Definition: lnp.h:79
lnp_integrity_state_t
lnp_integrity_state_t
states for the integrity layer state machine
Definition: lnp.h:60
LNPwaitCRC
Definition: lnp.h:64
dlcd.h
Interface: direct control of LCD display.
LNPwaitRMH2
Definition: lnp.h:69
LNP_RCX_MSG_OP_LENGTH
#define LNP_RCX_MSG_OP_LENGTH
length of rcx message op, -3 because first 3 bytes is used to id sequence
Definition: lnp.h:56
lnp_init
void lnp_init(void)
Initialise protocol handlers.
LNPwaitHeader
Definition: lnp.h:61
lnp_addressing_handler_t
void(* lnp_addressing_handler_t)(const unsigned char *, unsigned char, unsigned char)
the addressing layer packet handler type
Definition: lnp.h:55
lnp_addressing_handler
volatile lnp_addressing_handler_t lnp_addressing_handler[]
addressing layer packets may be directed to a variety of ports.
dlcd_hide
#define dlcd_hide(a)
clear a segment directly in the LCD buffer
Definition: dlcd.h:180
lnp_timeout_reset
void lnp_timeout_reset(void)
reset the inter-byte timeout counter.
stdlib.h
Interface: reduced standard C library.
LNP_BYTE_TIMEOUT
#define LNP_BYTE_TIMEOUT
timeout waiting for a byte
Definition: lnp-logical.h:59
lnp_logical_write
int lnp_logical_write(const void *buf, size_t len)
Write buffer to IR port.
LNPwaitMH3
states when waiting for rcx message opcode
Definition: lnp.h:87
LNPwaitMH4
Definition: lnp.h:88
LNPwaitMCC
Definition: lnp.h:92
lnp-logical.h
Internal LNP Interface: link networking protocol logical layer.
LCD_IR_UPPER
#define LCD_IR_UPPER
Definition: dlcd.h:155
LNPwaitMN
Definition: lnp.h:89
LNPwaitRMH3
Definition: lnp.h:70

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

Generated for brickOS Kernel Developer by doxygen 1.8.16