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
70unsigned char lnp_hostaddr = (CONF_LNP_HOSTADDR << 4) & CONF_LNP_HOSTMASK;
71
73volatile unsigned short lnp_timeout_counter;
74
76unsigned short lnp_timeout=LNP_BYTE_TIMEOUT;
77
80
82
85
87
91
92#if !defined(CONF_MM)
93static char lnp_buffer[260];
94#endif // CONF_MM
95
96#if defined(CONF_RCX_PROTOCOL)
99
101const unsigned char lnp_rcx_header[LNP_RCX_HEADER_LENGTH] = {0xff,0x00};
102
104const unsigned char lnp_rcx_remote_op[LNP_RCX_REMOTE_OP_LENGTH] = {0xd2,0x2d};
105
106
108unsigned char lnp_rcx_temp0;
109unsigned char lnp_rcx_temp1;
110
112unsigned char lnp_rcx_checksum;
113
114#endif
115
116#if defined(CONF_RCX_MESSAGE)
118const unsigned char lnp_rcx_msg_op[LNP_RCX_MSG_OP_LENGTH] = {0xf7,0x08};
119
121unsigned 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
135unsigned 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
177int 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
198int 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
221void 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
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
251#endif
252 addrh(data,length-2,src);
253 }
254 }
255 }
256
257 } // switch(header)
258}
259
261void 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
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)
445void lnp_integrity_reset(void) {
446#else
447HANDLER_WRAPPER("lnp_integrity_reset","lnp_integrity_reset_core");
448void lnp_integrity_reset_core(void) {
449#endif
450#ifndef CONF_HOST
451 if(tx_state>TX_IDLE) {
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
472int lnp_integrity_active(void) {
474}
475
477#if defined(CONF_RCX_COMPILER) || defined(CONF_HOST)
478void lnp_timeout_reset(void) {
479#else
480HANDLER_WRAPPER("lnp_timeout_reset","lnp_timeout_reset_core");
481void lnp_timeout_reset_core(void) {
482#endif
484}
485
487
489void lnp_timeout_set(unsigned short timeout) {
491}
492
494
496void 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
519int 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
__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\ ")
#define CONF_LNP_HOSTMASK
LNP host mask.
Definition: config.h:58
#define CONF_LNP_HOSTADDR
LNP host address.
Definition: config.h:54
Interface: direct control of LCD display.
#define LCD_IR_LOWER
Definition: dlcd.h:154
#define LCD_IR_UPPER
Definition: dlcd.h:155
#define dlcd_hide(a)
clear a segment directly in the LCD buffer
Definition: dlcd.h:180
#define dlcd_show(a)
set a segment directly in the LCD buffer
Definition: dlcd.h:175
Internal LNP Interface: RCX redirected IRQ vectors.
HANDLER_WRAPPER("lcd_refresh_next_byte", "lcd_refresh_next_byte_core")
lcd refresh handler, called from system timer interrupt
void lcd_refresh(void)
refresh the entire LCD display
Definition: lcd.c:254
int lnp_logical_write(const void *buf, size_t len)
Write buffer to IR port.
int lnp_logical_range_is_far(void)
Test the IR transmitter range setting.
Definition: lnp-logical.h:73
volatile lnp_addressing_handler_t lnp_addressing_handler[]
addressing layer packets may be directed to a variety of ports.
int lnp_integrity_write(const unsigned char *data, unsigned char length)
send a LNP integrity layer packet of given length
lnp_remote_handler_t lnp_remote_handler
packets from remote have no ports
#define LNP_DUMMY_INTEGRITY
dummy integrity layer packet handler
Definition: lnp.h:58
wakeup_t msg_received(wakeup_t m)
wait until receive a message
void clear_msg(void)
clear last message from standard firmware
Definition: lnp.h:136
unsigned char lnp_hostaddr
LNP host address.
#define LNP_DUMMY_ADDRESSING
dummy addressing layer packet handler
Definition: lnp.h:61
unsigned char lnp_rcx_message
message variable
volatile lnp_integrity_handler_t lnp_integrity_handler
there are no ports for integrity layer packets, so there's just
void(* lnp_addressing_handler_t)(const unsigned char *, unsigned char, unsigned char)
the addressing layer packet handler type
Definition: lnp.h:55
void(* lnp_remote_handler_t)(unsigned int)
handler for remote
Definition: lnp.h:67
void(* lnp_integrity_handler_t)(const unsigned char *, unsigned char)
the integrity layer packet handler type
Definition: lnp.h:50
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
#define LNP_DUMMY_REMOTE
dummy remote packet handler
Definition: lnp.h:70
int send_msg(unsigned char msg)
send a standard firmware message
Interface: reduced standard C library.
void * malloc(size_t size)
allocate and return pointer to uninitialized memory
void free(void *ptr)
return the allocated memory to memory management.
Interface: string functions.
Internal Interface: LCD control and constants.
Internal LNP Interface: link networking protocol logical layer.
volatile signed char tx_state
transmit status
#define TX_IDLE
not transmitting, last xmit OK
Definition: lnp-logical.h:67
#define TX_COLL
not transmitting, last xmit was collision
Definition: lnp-logical.h:66
void txend_handler(void)
Callback: end of transmission.
#define LNP_BYTE_TIMEOUT
timeout waiting for a byte
Definition: lnp-logical.h:59
Internal LNP Interface: link networking protocol.
void lnp_integrity_byte(unsigned char b)
receive a byte from the physical layer, decoding integrity layer packets.
void lnp_integrity_reset(void)
reset the integrity layer on error or timeout.
lnp_integrity_state_t
states for the integrity layer state machine
Definition: lnp.h:60
@ LNPwaitMH4
Definition: lnp.h:88
@ LNPwaitRC
Definition: lnp.h:81
@ LNPwaitRMH2
Definition: lnp.h:69
@ LNPwaitRB0I
Definition: lnp.h:78
@ LNPwaitRB0
states when waiting for remote buttons args
Definition: lnp.h:77
@ LNPwaitLength
Definition: lnp.h:62
@ LNPwaitHeader
Definition: lnp.h:61
@ LNPwaitRMH4
Definition: lnp.h:71
@ LNPwaitRB1
Definition: lnp.h:79
@ LNPwaitData
Definition: lnp.h:63
@ LNPwaitMH3
states when waiting for rcx message opcode
Definition: lnp.h:87
@ LNPwaitRCI
Definition: lnp.h:82
@ LNPwaitMN
Definition: lnp.h:89
@ LNPwaitMCC
Definition: lnp.h:92
@ LNPwaitMC
Definition: lnp.h:91
@ LNPwaitMNC
Definition: lnp.h:90
@ LNPwaitCRC
Definition: lnp.h:64
@ LNPwaitRB1I
Definition: lnp.h:80
@ LNPwaitRMH3
Definition: lnp.h:70
@ LNPwaitRMH1
states when waiting for rcx protocol message
Definition: lnp.h:68
#define LNP_RCX_HEADER_LENGTH
length of header from remote/rcx, -1 because first byte is used to id sequence
Definition: lnp.h:50
lnp_integrity_state_t lnp_integrity_state
the integrity layer state
#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
unsigned short lnp_timeout
the timeout length in ms
#define LNP_HOSTMASK
the LNP host mask (config.h)
Definition: lnp.h:43
void lnp_timeout_reset(void)
reset the inter-byte timeout counter.
#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
volatile unsigned short lnp_timeout_counter
the timeout counter in ms
unsigned char lnp_checksum_copy(unsigned char *dest, const unsigned char *data, unsigned length)
the LNP ‘copy and compute checksum’ function.
void lnp_timeout_set(unsigned short timeout)
set the inter-byte timeout and reset the timeout counter to that value.
Definition: lnp.h:155
void lnp_init(void)
Initialise protocol handlers.
#define LNP_PORTMASK
LNP port mask is derived from host mask.
Definition: lnp.h:46
int lnp_integrity_active(void)
return whether a packet is currently being received
Definition: lnp.h:140
Internal Interface: Powerdown Timer Routines.
void shutoff_restart(void)
unsigned long wakeup_t
wakeup data area type
Definition: tm.h:57

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

Generated for brickOS Kernel Developer by doxygen 1.9.4