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 * Chris Dearman <chris@algor.co.uk> 00025 * Martin Cornelius <Martin.Cornelius@t-online.de> 00026 */ 00027 00028 #include <sys/lnp-logical.h> 00029 00030 #ifdef CONF_LNP 00031 00032 #include <sys/lnp.h> 00033 00034 #include <sys/h8.h> 00035 #include <sys/irq.h> 00036 00037 #ifdef CONF_AUTOSHUTOFF 00038 #include <sys/timeout.h> 00039 #endif 00040 00041 #include <time.h> 00042 #include <mem.h> 00043 #include <semaphore.h> 00044 #include <unistd.h> 00045 00046 #include <rom/registers.h> 00047 00049 // 00050 // Variables 00051 // 00053 00054 static const unsigned char *tx_ptr; 00055 static const unsigned char *tx_verify; 00056 static const unsigned char *tx_end; 00057 00058 volatile signed char tx_state; 00059 00061 00066 static time_t allow_tx; 00067 00068 #ifdef CONF_TM 00069 static sem_t tx_sem; 00070 #endif 00071 00073 // 00074 // Functions 00075 // 00077 00078 #ifdef CONF_RCX_COMPILER 00079 static void rx_handler(void) __attribute__ ((rcx_interrupt)); 00080 static void rxerror_handler(void) __attribute__ ((rcx_interrupt)); 00081 static void tx_handler(void) __attribute__ ((rcx_interrupt)); 00082 void txend_handler(void) __attribute__ ((rcx_interrupt)); 00083 #else 00084 void rx_handler(void); 00085 void rxerror_handler(void); 00086 void tx_handler(void); 00087 void txend_handler(void); 00088 #endif 00089 00090 00092 extern inline void carrier_init(void) { 00093 T1_CR =0x9; 00094 T1_CSR =0x13; 00095 T1_CORA=0x1a; 00096 } 00097 00099 extern inline void carrier_shutdown(void) { 00100 T1_CR =0; 00101 T1_CSR =0; 00102 } 00103 00105 // 00106 #ifdef CONF_RCX_COMPILER 00107 static void rx_handler(void) { 00108 #else 00109 HANDLER_WRAPPER("rx_handler","rx_core"); 00110 void rx_core(void) { 00111 #endif 00112 time_t new_tx; 00113 lnp_timeout_reset(); 00114 if(tx_state<TX_ACTIVE) { 00115 // foreign bytes 00116 // 00117 new_tx = get_system_up_time()+LNP_BYTE_SAFE; 00118 if (new_tx > allow_tx) allow_tx = new_tx; 00119 lnp_integrity_byte(S_RDR); 00120 } else { 00121 // echos of own bytes -> collision detection 00122 // 00123 if(S_RDR!=*tx_verify) { 00124 txend_handler(); 00125 tx_state=TX_COLL; 00126 } else if( tx_end <= ++tx_verify ) { 00127 // let transmission end handler handle things 00128 // 00129 tx_state=TX_IDLE; 00130 } 00131 } 00132 00133 // suppress volatile modifier to generate bit instruction. 00134 // 00135 *((char*) &S_SR) &=~SSR_RECV_FULL; 00136 } 00137 00139 // 00140 #ifdef CONF_RCX_COMPILER 00141 static void rxerror_handler(void) { 00142 #else 00143 HANDLER_WRAPPER("rxerror_handler","rxerror_core"); 00144 void rxerror_core(void) { 00145 #endif 00146 time_t new_tx; 00147 if(tx_state<TX_ACTIVE) { 00148 lnp_integrity_reset(); 00149 new_tx = get_system_up_time()+LNP_BYTE_SAFE; 00150 if (new_tx > allow_tx) allow_tx = new_tx; 00151 } else { 00152 txend_handler(); 00153 tx_state=TX_COLL; 00154 } 00155 00156 S_SR&=~SSR_ERRORS; 00157 } 00158 00160 // 00161 #ifdef CONF_RCX_COMPILER 00162 void txend_handler(void) { 00163 #else 00164 HANDLER_WRAPPER("txend_handler","txend_core"); 00165 void txend_core(void) { 00166 #endif 00167 // shutdown transmit and irqs, clear status flags 00168 // 00169 S_CR&=~(SCR_TX_IRQ | SCR_TRANSMIT | SCR_TE_IRQ); 00170 S_SR&=~(SSR_TRANS_EMPTY | SSR_TRANS_END); 00171 } 00172 00174 00176 #ifdef CONF_RCX_COMPILER 00177 static void tx_handler(void) { 00178 #else 00179 HANDLER_WRAPPER("tx_handler","tx_core"); 00180 void tx_core(void) { 00181 #endif 00182 if(tx_ptr<tx_end) { 00183 // transmit next byte 00184 // 00185 S_TDR = *(tx_ptr++); 00186 *((char*) &S_SR)&=~SSR_TRANS_EMPTY; 00187 } else { 00188 // disable transmission interrupt 00189 // 00190 S_CR&=~SCR_TX_IRQ; 00191 } 00192 } 00193 00195 void lnp_logical_shutdown(void) { 00196 S_CR =0; // everything off 00197 carrier_shutdown(); 00198 lnp_logical_range(0); 00199 00200 tx_state=TX_IDLE; 00201 allow_tx=0; 00202 00203 #ifdef CONF_TM 00204 sem_destroy(&tx_sem); 00205 #endif 00206 } 00207 00209 00211 void lnp_logical_init(void) { 00212 // safe initial state. 00213 // 00214 lnp_logical_shutdown(); 00215 00216 #ifdef CONF_TM 00217 sem_init(&tx_sem,0,1); 00218 #endif 00219 00220 // serial setup according to CONF_LNP_FAST / lnp_logical.h 00221 // was 8N1 fixed, now parity is also set. 00222 // 00223 S_MR =LNP_LOGICAL_PARITY; 00224 S_BRR=LNP_LOGICAL_BAUD_RATE; 00225 S_SR =0; 00226 00227 // carrier setup 00228 // 00229 rom_port4_ddr |= 1; // port 4 bit 0 output 00230 PORT4_DDR = rom_port4_ddr; 00231 carrier_init(); 00232 rom_port5_ddr = 4; // init p5ddr, for now 00233 PORT5_DDR = rom_port5_ddr; 00234 00235 // IRQ handler setup 00236 // 00237 eri_vector=&rxerror_handler; 00238 rxi_vector=&rx_handler; 00239 txi_vector=&tx_handler; 00240 tei_vector=&txend_handler; 00241 00242 // enable receiver and IRQs 00243 // 00244 S_CR=SCR_RECEIVE | SCR_RX_IRQ; 00245 } 00246 00247 00248 static wakeup_t write_allow(wakeup_t data) { 00249 return get_system_up_time() >= *((volatile time_t*)&allow_tx); 00250 } 00251 00252 static wakeup_t write_complete(wakeup_t data) { 00253 return *((volatile signed char*)&tx_state)<TX_ACTIVE; 00254 } 00255 00257 00261 int lnp_logical_write(const void* buf,size_t len) { 00262 unsigned char tmp; 00263 00264 #ifdef CONF_TM 00265 if (sem_wait(&tx_sem) == -1) 00266 return tx_state; 00267 #endif 00268 00269 #ifdef CONF_AUTOSHUTOFF 00270 shutoff_restart(); 00271 #endif 00272 00273 if (wait_event(write_allow,0) != 0) 00274 { 00275 lnp_timeout_reset(); 00276 00277 tx_verify=tx_ptr=buf; // what to transmit 00278 tx_end=buf+len; 00279 00280 tx_state=TX_ACTIVE; 00281 S_SR&=~(SSR_TRANS_EMPTY | SSR_TRANS_END); // clear flags 00282 S_CR|=SCR_TRANSMIT | SCR_TX_IRQ | SCR_TE_IRQ; // enable transmit & irqs 00283 00284 wait_event(write_complete,0); 00285 00286 // determine delay before next transmission 00287 // 00288 if(tx_state==TX_IDLE) 00289 tmp=LNP_WAIT_TXOK; 00290 else 00291 tmp=LNP_WAIT_COLL + ( ((unsigned char) 0x0f) & 00292 ( ((unsigned char) len)+ 00293 ((unsigned char*)buf)[len-1]+ 00294 ((unsigned char) get_system_up_time()) ) ); 00295 allow_tx=get_system_up_time()+tmp; 00296 } 00297 00298 #ifdef CONF_TM 00299 sem_post(&tx_sem); 00300 #endif 00301 00302 return tx_state; 00303 } 00304 00305 #endif // CONF_LNP
brickOS is released under the
Mozilla Public License.
Original code copyright 1998-2002 by the authors. |