00001 /********************************************************************************* 00002 00003 Copyright 2006-2008 MakingThings 00004 00005 Licensed under the Apache License, 00006 Version 2.0 (the "License"); you may not use this file except in compliance 00007 with the License. You may obtain a copy of the License at 00008 00009 http://www.apache.org/licenses/LICENSE-2.0 00010 00011 Unless required by applicable law or agreed to in writing, software distributed 00012 under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 00013 CONDITIONS OF ANY KIND, either express or implied. See the License for 00014 the specific language governing permissions and limitations under the License. 00015 00016 *********************************************************************************/ 00017 00018 /** \file system.c 00019 System Control. 00020 Functions for monitoring and controlling the system. 00021 */ 00022 00023 #include "stdio.h" 00024 #include "string.h" 00025 #include "ctype.h" 00026 #include "io.h" 00027 #include "eeprom.h" 00028 #include "system.h" 00029 #include "config.h" 00030 #include "AT91SAM7X256.h" 00031 #include "portmacro.h" 00032 #include "FreeRTOSConfig.h" 00033 #include "network.h" 00034 00035 /* the Atmel header file doesn't define these. */ 00036 #ifdef AT91SAM7X256_H 00037 # define AT91C_RSTC_KEY_PASSWORD (0xa5 << 24) 00038 00039 # define AT91C_IROM ((char *)(0x3 << 20)) 00040 # define AT91C_IROM_SIZE (8 << 10) 00041 #endif 00042 00043 int PortFreeMemory( void ); 00044 void StackAuditTask( void* p ); 00045 void kill( void ); 00046 void vPortDisableAllInterrupts( void ); 00047 #define ASYNC_INIT -10 00048 #define ASYNC_INACTIVE -1 00049 00050 typedef struct System_ 00051 { 00052 char name[ SYSTEM_MAX_NAME + 1 ]; // allotted EEPROM space is 100, but leave room for \0! 00053 int users; 00054 void* StackAuditPtr; 00055 #ifdef OSC 00056 char scratch1[ OSC_SCRATCH_SIZE ]; 00057 int asyncDestination; 00058 int autoInterval; 00059 #endif // OSC 00060 } SystemS; 00061 00062 SystemS* System; 00063 00064 /** \defgroup System System 00065 The System subsystem monitors and controls several aspects of the system. 00066 00067 * \ingroup Core 00068 * @{ 00069 */ 00070 00071 /** 00072 Sets whether the System subsystem is active. 00073 @param state An integer specifying the state system 00074 @return Zero on success. 00075 00076 \b Example 00077 \code 00078 // enable the System subsystem 00079 System_SetActive(1); 00080 \endcode 00081 */ 00082 int System_SetActive( int state ) 00083 { 00084 if( state ) 00085 { 00086 if( System == NULL ) 00087 { 00088 System = MallocWait( sizeof( SystemS ), 100 ); 00089 System->name[0] = 0; 00090 System->StackAuditPtr = NULL; 00091 #ifdef OSC 00092 System->asyncDestination = ASYNC_INIT; 00093 System->asyncDestination = System_GetAsyncDestination( ); 00094 System->autoInterval = ASYNC_INIT; 00095 System->autoInterval = System_GetAutoSendInterval( ); 00096 #endif 00097 } 00098 return CONTROLLER_OK; 00099 } 00100 else 00101 { 00102 if ( System != NULL ) 00103 { 00104 Free( System ); 00105 System = NULL; 00106 } 00107 return CONTROLLER_OK; 00108 } 00109 } 00110 00111 /** 00112 Returns the active state of the subsystem. 00113 @return The active state of the subsystem - 1 (active) or 0 (inactive). 00114 00115 \b Example 00116 \code 00117 if(System_GetActive()) 00118 { 00119 // System is active 00120 } 00121 else 00122 { 00123 // System is inactive 00124 } 00125 \endcode 00126 */ 00127 int System_GetActive( ) 00128 { 00129 return System != NULL; 00130 } 00131 00132 /** 00133 Returns the free size of the heap. 00134 The heap size is set in config.h in the constant CONTROLLER_HEAPSIZE. 00135 Any calls to Malloc will take their memory from the heap. This allows 00136 you to check how much heap is remaining. 00137 @return The size free memory. 00138 00139 \b Example 00140 \code 00141 // see how much memory is available 00142 int freemem = System_GetFreeMemory(); 00143 \endcode 00144 */ 00145 int System_GetFreeMemory( void ) 00146 { 00147 return PortFreeMemory(); 00148 } 00149 00150 /** 00151 Gets the board's Serial Number. 00152 Each board has a serial number, although it's not necessarily unique 00153 as you can reset it as you please. 00154 00155 The serial number is used to determine the Ethernet MAC address, so boards 00156 on the same network need to have unique serial numbers. 00157 @return CONTROLLER_OK ( = 0 ). 00158 00159 \b Example 00160 \code 00161 // get this board's serial number 00162 int sernum = System_GetSerialNumber(); 00163 \endcode 00164 */ 00165 int System_GetSerialNumber( void ) 00166 { 00167 int serial; 00168 if ( Eeprom_Read( EEPROM_SYSTEM_SERIAL_NUMBER, (uchar*)&serial, 4 ) == CONTROLLER_OK ) 00169 return serial & 0xFFFF; 00170 return 0; 00171 } 00172 00173 /** 00174 Sets the Serial Number. 00175 Note that this can be changed by the user at 00176 any time, but that it is used in the \ref Network subsystem to form the last 00177 two bytes of the network MAC address, so ideally units on the same network 00178 should have unique serial numbers. 00179 @return 0 on success. 00180 00181 \b Example 00182 \code 00183 // set the serial number to 12345 00184 System_SetSerialNumber(12345); 00185 \endcode 00186 */ 00187 int System_SetSerialNumber( int serial ) 00188 { 00189 serial &= 0xFFFF; 00190 return Eeprom_Write( EEPROM_SYSTEM_SERIAL_NUMBER, (uchar*)&serial, 4 ); 00191 } 00192 00193 /** 00194 Returns the board to SAM-BA mode. 00195 When a board is in SAM-BA mode, it is ready to have new firmware uploaded to it. 00196 Upon successful completion, the board will be reset and begin running SAM-BA. 00197 This function does not clear the GPNVM2 bit, so if you unplug/replug you'll be running 00198 your old code again. 00199 @param sure Confirm you're sure you want to do this. 00200 @return nonzero on failure. Successful completion does not return. 00201 00202 \b Example 00203 \code 00204 // prepare to be uploaded 00205 System_SetSamba(1); 00206 \endcode 00207 */ 00208 int System_SetSamba( int sure ) 00209 { 00210 if ( sure ) 00211 { 00212 vPortDisableAllInterrupts(); 00213 00214 /* Disable the USB pullup. */ 00215 #if ( CONTROLLER_VERSION == 90 ) 00216 AT91C_BASE_PIOB->PIO_PER = AT91C_PIO_PB11; 00217 AT91C_BASE_PIOB->PIO_OER = AT91C_PIO_PB11; 00218 AT91C_BASE_PIOB->PIO_SODR = AT91C_PIO_PB11; 00219 #elif ( CONTROLLER_VERSION == 95 || CONTROLLER_VERSION == 100 ) 00220 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA11; 00221 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA11; 00222 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA11; 00223 #elif ( CONTROLLER_VERSION == 200 ) 00224 AT91C_BASE_PIOA->PIO_PER = AT91C_PIO_PA30; 00225 AT91C_BASE_PIOA->PIO_OER = AT91C_PIO_PA30; 00226 AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA30; 00227 #endif 00228 00229 /* Steal the PIT for the pullup disable delay. */ 00230 AT91C_BASE_PITC->PITC_PIMR = ( 00231 (configCPU_CLOCK_HZ + (16 * 1000 / 2)) 00232 / (16 * 1000) 00233 ) | AT91C_PITC_PITEN 00234 ; 00235 00236 /* Dummy read to clear picnt. */ 00237 __asm__ __volatile__ ("ldr r3, %0" :: "m" (AT91C_BASE_PITC->PITC_PIVR) : "r3"); 00238 00239 /* Loop until picnt passes 200ms */ 00240 while((AT91C_BASE_PITC->PITC_PIIR & AT91C_PITC_PICNT) < (200 << 20)); 00241 00242 /* Reset onboard and offboard peripherals, but not processor */ 00243 while(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP); 00244 AT91C_BASE_RSTC->RSTC_RMR = AT91C_RSTC_KEY_PASSWORD; 00245 AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_KEY_PASSWORD 00246 | AT91C_RSTC_PERRST 00247 | AT91C_RSTC_EXTRST 00248 ; 00249 while(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP); 00250 00251 /* 00252 The ROM code copies itself to RAM, where it runs. 00253 That works fine when running SAM-BA in the usual way (booting with GPNVM2 clear). 00254 However, it is actually copying from the remap page; not the native ROM address. 00255 So with GPNVM2 set, that means the FLASH image (and only 8KB or so of that) gets copied, 00256 which is not a recipe for success. 00257 This workaround would be unnecessary if the ROM just copied itself from 0x300000 instead of 0x0. 00258 If not for the fact that the ROM code doesn't appear to issue a remap command (the exception vectors 00259 ordinarily remain in ROM instead of being remapped), this workaround would not be possible. Either 00260 it doesn't remap or it does it an even number of times. To address the problem, we copy the ROM 00261 image to the RAM, ourselves and issue a remap so that when we run the image, RAM will already be remapped, 00262 and the image copy that it performs will be from the RAM to itself, therefore harmless. This does have 00263 the side effect that when SAM-BA runs other code (via the G command), the remap page will be 00264 remapped to RAM. Any code run that way which assumes otherwise will break. We are not using SAM-BA 00265 in that way. 00266 */ 00267 00268 /* From here on, we have to be in asm to prevent the compiler from trying to use RAM in any way. */ 00269 __asm__ __volatile__ ( 00270 /* Copy the ROM image to RAM. */ 00271 " mov r6, %0 \n" /* save ROM address for later */ 00272 " b 2f \n" 00273 "1: \n" 00274 " ldmia %0!, {r7} \n" 00275 " str r7, [%2] \n" 00276 " add %2, %2, #4 \n" 00277 "2: \n" 00278 " cmp %0, %1 \n" 00279 " bmi 1b \n" 00280 00281 /* Remap so that image copy in SAM-BA is RAM to RAM. */ 00282 /* We know that the remap page is not currently remapped because we just did an AT91C_RSTC_PERRST. */ 00283 " mov r7, %4 \n" 00284 " str r7, %3 \n" 00285 00286 /* Start running the ROM. */ 00287 " bx r6 \n" 00288 : 00289 : 00290 "r"(AT91C_IROM), 00291 "r"(AT91C_IROM + AT91C_IROM_SIZE), 00292 "r"(AT91C_ISRAM), 00293 "m"(AT91C_BASE_MC->MC_RCR), 00294 "n"(AT91C_MC_RCB) 00295 : 00296 "r7", "r6" 00297 ); 00298 } 00299 00300 // Never will do this 00301 return 1; 00302 } 00303 00304 /** 00305 Gives the board a name. 00306 The name must be alpha-numeric - only letters and numbers. It can help you 00307 determine one board from another when there are more than one connected to 00308 your system. 00309 @param name A string specifying the board's name 00310 @return 0 on success. 00311 00312 \b Example 00313 \code 00314 // give the board a special name 00315 System_SetName("my very special controller"); 00316 \endcode 00317 */ 00318 int System_SetName( char* name ) 00319 { 00320 System_SetActive( 1 ); 00321 int length = strlen( name ); 00322 if( length > SYSTEM_MAX_NAME ) 00323 return CONTROLLER_ERROR_STRING_TOO_LONG; 00324 00325 strcpy( System->name, name ); // update the name in our buffer 00326 int i; 00327 char* ptr = name; 00328 for( i = 0; i <= length; i++ ) // have to do this because Eeprom_Write can only go 32 at a time. 00329 { 00330 Eeprom_Write( EEPROM_SYSTEM_NAME + i, (uchar*)ptr++, 1 ); 00331 } 00332 00333 return CONTROLLER_OK; 00334 } 00335 00336 /** 00337 Read the board's name. 00338 @return The board's name as a string. 00339 00340 \b Example 00341 \code 00342 char* board_name = System_GetName(); 00343 \endcode 00344 */ 00345 char* System_GetName( ) 00346 { 00347 System_SetActive( 1 ); 00348 if( System->name[0] == 0 ) 00349 { 00350 char* ptr; 00351 ptr = System->name; 00352 int i; 00353 bool legal = false; 00354 for( i = 0; i <= SYSTEM_MAX_NAME; i++ ) 00355 { 00356 Eeprom_Read( EEPROM_SYSTEM_NAME + i, (uchar*)ptr, 1 ); 00357 if( *ptr == 0 ) 00358 break; 00359 if( !isalnum( *ptr ) && *ptr != ' ' ) 00360 { 00361 legal = false; 00362 break; 00363 } 00364 legal = true; 00365 00366 if( i == SYSTEM_MAX_NAME && *ptr != 0 ) 00367 *ptr = 0; 00368 ptr++; 00369 } 00370 00371 if( !legal ) 00372 { 00373 strcpy( System->name, "Make Controller Kit" ); 00374 System_SetName( System->name ); 00375 } 00376 } 00377 00378 return System->name; 00379 } 00380 00381 /** 00382 Reset the board. 00383 Will reboot the board if the parameter sure is true. 00384 @param sure confirms the request is true. 00385 @return 0 on success. 00386 00387 \b Example 00388 \code 00389 // reboot 00390 System_SetReset(1); 00391 \endcode 00392 */ 00393 int System_SetReset( int sure ) 00394 { 00395 if ( sure ) 00396 kill( ); 00397 00398 return 1; 00399 } 00400 00401 /** @} 00402 */ 00403 00404 void kill( void ) 00405 { 00406 AT91C_BASE_RSTC->RSTC_RCR = ( AT91C_RSTC_EXTRST | AT91C_RSTC_PROCRST | AT91C_RSTC_PERRST | (0xA5 << 24 ) ); 00407 } 00408 00409 #ifdef OSC 00410 #include "osc.h" 00411 00412 void System_StackAudit( int on_off ) 00413 { 00414 System_SetActive( 1 ); 00415 if( System->StackAuditPtr == NULL && on_off ) 00416 System->StackAuditPtr = TaskCreate( StackAuditTask, "StackAudit", 700, 0, 5 ); 00417 00418 if( System->StackAuditPtr != NULL && !on_off ) 00419 { 00420 TaskDelete( System->StackAuditPtr ); 00421 System->StackAuditPtr = NULL; 00422 } 00423 } 00424 00425 void StackAuditTask( void* p ) 00426 { 00427 (void)p; 00428 void* task = NULL; 00429 while( 1 ) 00430 { 00431 task = TaskGetNext( task ); 00432 int stackremaining = TaskGetRemainingStack( task ); 00433 if( stackremaining < 50 ) 00434 { 00435 Led_SetState( 1 ); 00436 Debug( DEBUG_WARNING, "Warning: Stack running low on task %s. %d bytes left.", TaskGetName( task ), stackremaining ); 00437 } 00438 00439 int freemem = System_GetFreeMemory( ); 00440 if( freemem < 100 ) 00441 { 00442 Led_SetState( 1 ); 00443 Debug( DEBUG_WARNING, "Warning: System memory running low. %d bytes left.", freemem ); 00444 } 00445 00446 Sleep( 5 ); 00447 } 00448 } 00449 00450 void System_SetAsyncDestination( int dest ) 00451 { 00452 System_SetActive( 1 ); 00453 if( dest < ASYNC_INACTIVE || dest > (OSC_CHANNEL_COUNT-1) ) 00454 return; 00455 else 00456 { 00457 if( System->asyncDestination != dest ) 00458 { 00459 System->asyncDestination = dest; 00460 Eeprom_Write( EEPROM_OSC_ASYNC_DEST, (uchar*)&dest, 4 ); 00461 } 00462 } 00463 } 00464 00465 int System_GetAsyncDestination( ) 00466 { 00467 System_SetActive( 1 ); 00468 if( System->asyncDestination == ASYNC_INIT ) 00469 { 00470 int async; 00471 Eeprom_Read( EEPROM_OSC_ASYNC_DEST, (uchar*)&async, 4 ); 00472 if( async >= 0 && async <= (OSC_CHANNEL_COUNT-1) ) 00473 System->asyncDestination = async; 00474 else 00475 System->asyncDestination = ASYNC_INACTIVE; 00476 } 00477 return System->asyncDestination; 00478 } 00479 00480 void System_SetAutoSendInterval( int interval ) 00481 { 00482 System_SetActive( 1 ); 00483 if( interval < 0 || interval > 5000 ) 00484 return; 00485 else 00486 { 00487 if( System->autoInterval != interval ) 00488 { 00489 System->autoInterval = interval; 00490 Eeprom_Write( EEPROM_OSC_ASYNC_INTERVAL, (uchar*)&interval, 4 ); 00491 } 00492 } 00493 } 00494 00495 int System_GetAutoSendInterval( ) 00496 { 00497 System_SetActive( 1 ); 00498 if( System->autoInterval == ASYNC_INIT ) 00499 { 00500 int interval; 00501 Eeprom_Read( EEPROM_OSC_ASYNC_INTERVAL, (uchar*)&interval, 4 ); 00502 if( interval >= 0 && interval <= 5000 ) 00503 System->autoInterval = interval; 00504 else 00505 System->autoInterval = 10; 00506 } 00507 return System->autoInterval; 00508 } 00509 00510 /** \defgroup SystemOSC System - OSC 00511 System controls many of the logistics of the Controller Board via OSC. 00512 \ingroup OSC 00513 00514 \section devices Devices 00515 There's only one System, so a device index is not used in OSC messages to it. 00516 00517 \section properties Properties 00518 System has eight properties: 00519 - name 00520 - freememory 00521 - samba 00522 - reset 00523 - serialnumber 00524 - version 00525 - stack-audit 00526 - task-report 00527 - active 00528 00529 \par Name 00530 The \b name property allows you to give a board its own name. The name can only contain 00531 alphabetic characters and numbers. 00532 To set your board's name, send the message 00533 \verbatim /system/name "My Board"\endverbatim 00534 To read the board's name, send the message 00535 \verbatim /system/name \endverbatim 00536 The board will respond by sending back an OSC message with the board's name. 00537 00538 \par Free Memory 00539 The \b freememory property corresponds to the amount of free memory on the Controller Board. 00540 This value is read-only. To get the amount of free memory, send the message 00541 \verbatim /system/freememory \endverbatim 00542 The board will respond by sending back an OSC message with the amount of free memory. 00543 00544 \par Samba 00545 The \b samba property is a write-only value that returns the board to a state in which it's ready 00546 to receive new firmware via SAM-BA or mchelper. Once you've set the board to SAM-BA state, 00547 unplug and replug the power on the board before uploading new firmware. 00548 \par 00549 To set the board in SAM-BA state, send the message 00550 \verbatim /system/samba 1 \endverbatim 00551 and don't forget to power cycle the board. Remember the board won't be able to send/receive OSC 00552 messages until a new program is uploaded to it. 00553 00554 \par Reset 00555 The \b reset property is a write-only value that reboots the board. 00556 To reset the board, send the message 00557 \verbatim /system/reset 1 \endverbatim 00558 00559 \par Serial Number 00560 The \b serialnumber property corresponds to the unique serial number on each Controller Board. 00561 This value can be used in situations where a unique value needs to be used to identify a board. 00562 The serial number can be both read and written. 00563 \par 00564 To read the board's serial number, send the message 00565 \verbatim /system/serialnumber \endverbatim 00566 00567 \par Version 00568 The \b version property corresponds to the of the firmware currently running on the board. 00569 This is read-only. 00570 \par 00571 To read the board's version, send the message 00572 \verbatim /system/version \endverbatim 00573 00574 \par Stack Audit 00575 The \b stack-audit property can fire up a task that will monitor the stack usage 00576 of all tasks running on the board. If the remaining stack of any of the tasks drops below 50 bytes, 00577 the board will attempt to send an OSC message back via the \ref Debug system to let you know. 00578 \par 00579 This uses up quite a lot of processor time, so it's really only designed to be used in a 00580 debug context. 00581 \par 00582 To start up the stack audit, send the message 00583 \verbatim /system/stack-audit 1 \endverbatim 00584 \par 00585 and turn it off by sending 00586 \verbatim /system/stack-audit 0 \endverbatim 00587 00588 \par Task Report 00589 The \b task-report property is a read-only property that will generate a list of all the tasks running 00590 on your Make Controller, first giving the name of the task followed by the task's remaining stack. 00591 \par 00592 To see the tasks running on your board, send the message 00593 \verbatim /system/task-report \endverbatim 00594 00595 \par Active 00596 The \b active property corresponds to the active state of System. 00597 If System is set to be inactive, it will not respond to any other OSC messages. 00598 If you're not seeing appropriate 00599 responses to your messages to System, check the whether it's 00600 active by sending a message like 00601 \verbatim /system/active \endverbatim 00602 \par 00603 You can set the active flag by sending 00604 \verbatim /system/active 1 \endverbatim 00605 */ 00606 00607 static char* SystemOsc_Name = "system"; 00608 static char* SystemOsc_PropertyNames[] = { "active", "freememory", "samba", "reset", 00609 "serialnumber", "version", 00610 "name", "info-internal", "info", "stack-audit", 00611 "task-report", "autosend-usb", "autosend-udp", "autosend-interval", 0 }; // must have a trailing 0 00612 00613 int SystemOsc_PropertySet( int property, char* typedata, int channel ); 00614 int SystemOsc_PropertyGet( int property, int channel ); 00615 00616 const char* SystemOsc_GetName( void ) 00617 { 00618 return SystemOsc_Name; 00619 } 00620 // need to allow this to accept non-int arguments 00621 int SystemOsc_ReceiveMessage( int channel, char* message, int length ) 00622 { 00623 int status = Osc_GeneralReceiverHelper( channel, message, length, 00624 SystemOsc_Name, 00625 SystemOsc_PropertySet, SystemOsc_PropertyGet, 00626 SystemOsc_PropertyNames ); 00627 00628 if ( status != CONTROLLER_OK ) 00629 return Osc_SendError( channel, SystemOsc_Name, status ); 00630 00631 return CONTROLLER_OK; 00632 } 00633 00634 int SystemOsc_Poll( ) 00635 { 00636 return CONTROLLER_OK; 00637 } 00638 00639 // Set the index LED, property with the value 00640 int SystemOsc_PropertySet( int property, char* typedata, int channel ) 00641 { 00642 int value = 0; 00643 switch ( property ) 00644 { 00645 case 0: // active 00646 { 00647 int count = Osc_ExtractData( typedata, "i", &value ); 00648 if ( count != 1 ) 00649 return Osc_SubsystemError( channel, SystemOsc_Name, "Incorrect data - need an int" ); 00650 00651 System_SetActive( value ); 00652 break; 00653 } 00654 case 2: // samba 00655 { 00656 int count = Osc_ExtractData( typedata, "i", &value ); 00657 if ( count != 1 ) 00658 return Osc_SubsystemError( channel, SystemOsc_Name, "Incorrect data - need an int" ); 00659 00660 System_SetSamba( value ); 00661 break; 00662 } 00663 case 3: // reset 00664 { 00665 int count = Osc_ExtractData( typedata, "i", &value ); 00666 if ( count != 1 ) 00667 return Osc_SubsystemError( channel, SystemOsc_Name, "Incorrect data - need an int" ); 00668 00669 System_SetReset( value ); 00670 break; 00671 } 00672 case 4: // serialnumber 00673 { 00674 int count = Osc_ExtractData( typedata, "i", &value ); 00675 if ( count != 1 ) 00676 return Osc_SubsystemError( channel, SystemOsc_Name, "Incorrect data - need an int" ); 00677 00678 System_SetSerialNumber( value ); 00679 break; 00680 } 00681 case 6: // name 00682 { 00683 char* address; 00684 int count = Osc_ExtractData( typedata, "s", &address ); 00685 if ( count != 1 ) 00686 return Osc_SubsystemError( channel, SystemOsc_Name, "Incorrect data - need a string" ); 00687 00688 System_SetName( address ); 00689 break; 00690 } 00691 case 9: // stack-audit 00692 { 00693 int count = Osc_ExtractData( typedata, "i", &value ); 00694 if ( count != 1 ) 00695 return Osc_SubsystemError( channel, SystemOsc_Name, "Incorrect data - need an int" ); 00696 00697 System_StackAudit( value ); 00698 break; 00699 } 00700 case 11: // autosend-usb 00701 { 00702 int count = Osc_ExtractData( typedata, "i", &value ); 00703 if ( count != 1 ) 00704 return Osc_SubsystemError( channel, SystemOsc_Name, "Incorrect data - need an int" ); 00705 if( value ) 00706 System_SetAsyncDestination( OSC_CHANNEL_USB ); 00707 else 00708 { 00709 if( System_GetAsyncDestination( ) == OSC_CHANNEL_USB ) 00710 System_SetAsyncDestination( ASYNC_INACTIVE ); 00711 } 00712 break; 00713 } 00714 case 12: // autosend-udp 00715 { 00716 int count = Osc_ExtractData( typedata, "i", &value ); 00717 if ( count != 1 ) 00718 return Osc_SubsystemError( channel, SystemOsc_Name, "Incorrect data - need an int" ); 00719 if( value ) 00720 System_SetAsyncDestination( OSC_CHANNEL_UDP ); 00721 else 00722 { 00723 if( System_GetAsyncDestination( ) == OSC_CHANNEL_UDP ) 00724 System_SetAsyncDestination( ASYNC_INACTIVE ); 00725 } 00726 break; 00727 } 00728 case 13: // autosend-interval 00729 { 00730 int count = Osc_ExtractData( typedata, "i", &value ); 00731 if ( count != 1 ) 00732 return Osc_SubsystemError( channel, SystemOsc_Name, "Incorrect data - need an int" ); 00733 00734 System_SetAutoSendInterval( value ); 00735 break; 00736 } 00737 } 00738 return CONTROLLER_OK; 00739 } 00740 00741 // Get the property 00742 int SystemOsc_PropertyGet( int property, int channel ) 00743 { 00744 int value = 0; 00745 //char address[ OSC_SCRATCH_SIZE ]; 00746 switch ( property ) 00747 { 00748 case 0: // active 00749 value = System_GetActive( ); 00750 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00751 Osc_CreateMessage( channel, System->scratch1, ",i", value ); 00752 break; 00753 case 1: // freememory 00754 value = System_GetFreeMemory( ); 00755 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00756 Osc_CreateMessage( channel, System->scratch1, ",i", value ); 00757 break; 00758 case 4: // serialnumber 00759 value = System_GetSerialNumber( ); 00760 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00761 Osc_CreateMessage( channel, System->scratch1, ",i", value ); 00762 break; 00763 case 5: // version 00764 { 00765 char versionString[50]; 00766 snprintf( versionString, 50, "%s %d.%d.%d", FIRMWARE_NAME, FIRMWARE_MAJOR_VERSION, FIRMWARE_MINOR_VERSION, FIRMWARE_BUILD_NUMBER ); 00767 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00768 Osc_CreateMessage( channel, System->scratch1, ",s", versionString ); 00769 break; 00770 } 00771 case 6: // name 00772 { 00773 char* name; 00774 name = System_GetName( ); 00775 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00776 Osc_CreateMessage( channel, System->scratch1, ",s", name ); 00777 break; 00778 } 00779 case 7: // info-internal 00780 case 8: // info 00781 { 00782 int a0, a1, a2, a3; 00783 { // put these in their own context so the local variables aren't lying around on the stack for the whole message 00784 char ipAddr[25]; 00785 char* sysName = System_GetName( ); 00786 int serialnum = System_GetSerialNumber( ); 00787 char sysVersion[25]; 00788 snprintf( sysVersion, 25, "%s %d.%d.%d", FIRMWARE_NAME, FIRMWARE_MAJOR_VERSION, FIRMWARE_MINOR_VERSION, FIRMWARE_BUILD_NUMBER ); 00789 int freemem = System_GetFreeMemory( ); 00790 #ifdef MAKE_CTRL_NETWORK 00791 if( Network_GetAddress( &a0, &a1, &a2, &a3 ) != CONTROLLER_OK ) 00792 a0 = a1 = a2 = a3 = -1; 00793 #else 00794 a0 = a1 = a2 = a3 = -1; 00795 #endif // MAKE_CTRL_NETWORK 00796 snprintf( ipAddr, 25, "%d.%d.%d.%d", a0, a1, a2, a3 ); 00797 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s-a", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00798 Osc_CreateMessage( channel, System->scratch1, ",sissi", sysName, serialnum, ipAddr, sysVersion, freemem ); 00799 } 00800 { 00801 char gateway[25]; 00802 char mask[25]; 00803 int dhcp; 00804 int webserver; 00805 int oscUdpListen; 00806 int oscUdpSend; 00807 #ifdef MAKE_CTRL_NETWORK 00808 if( Network_GetGateway( &a0, &a1, &a2, &a3 ) != CONTROLLER_OK ) 00809 a0 = a1 = a2 = a3 = -1; 00810 snprintf( gateway, 25, "%d.%d.%d.%d", a0, a1, a2, a3 ); 00811 if( Network_GetMask( &a0, &a1, &a2, &a3 ) != CONTROLLER_OK ) 00812 a0 = a1 = a2 = a3 = -1; 00813 snprintf( mask, 25, "%d.%d.%d.%d", a0, a1, a2, a3 ); 00814 dhcp = Network_GetDhcpEnabled( ); 00815 webserver = 0; // webserver no longer in core. TODO - update system-info to not use webserver 00816 oscUdpListen = NetworkOsc_GetUdpListenPort( ); 00817 oscUdpSend = NetworkOsc_GetUdpSendPort( ); 00818 #else 00819 a0 = a1 = a2 = a3 = -1; 00820 snprintf( gateway, 25, "%d.%d.%d.%d", a0, a1, a2, a3 ); 00821 snprintf( mask, 25, "%d.%d.%d.%d", a0, a1, a2, a3 ); 00822 dhcp = 0; 00823 webserver = 0; 00824 oscUdpListen = 0; 00825 oscUdpSend = 0; 00826 #endif // MAKE_CTRL_NETWORK 00827 00828 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s-b", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00829 Osc_CreateMessage( channel, System->scratch1, ",iissii", dhcp, webserver, gateway, mask, oscUdpListen, oscUdpSend ); 00830 } 00831 break; 00832 } 00833 case 9: // stack-audit 00834 if( System->StackAuditPtr == NULL ) 00835 value = 0; 00836 else 00837 value = 1; 00838 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00839 Osc_CreateMessage( channel, System->scratch1, ",i", value ); 00840 break; 00841 case 10: // task-report 00842 { 00843 int numOfTasks = GetNumberOfTasks( ) - 1; // don't count the IDLE task 00844 int i; 00845 void* task = NULL; 00846 char* taskName = ""; 00847 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00848 00849 for( i = 0; i < numOfTasks; i++ ) 00850 { 00851 task = TaskGetNext( task ); 00852 value = TaskGetRemainingStack( task ); 00853 taskName = TaskGetName( task ); 00854 Osc_CreateMessage( channel, System->scratch1, ",si", taskName, value ); 00855 } 00856 break; 00857 } 00858 case 11: // autosend-usb 00859 value = ( System_GetAsyncDestination( ) == OSC_CHANNEL_USB ) ? 1 : 0; 00860 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00861 Osc_CreateMessage( channel, System->scratch1, ",i", value ); 00862 break; 00863 case 12: // autosend-udp 00864 value = ( System_GetAsyncDestination( ) == OSC_CHANNEL_UDP ) ? 1 : 0; 00865 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00866 Osc_CreateMessage( channel, System->scratch1, ",i", value ); 00867 break; 00868 case 13: // autosend-interval 00869 value = System_GetAutoSendInterval( ); 00870 snprintf( System->scratch1, OSC_SCRATCH_SIZE, "/%s/%s", SystemOsc_Name, SystemOsc_PropertyNames[ property ] ); 00871 Osc_CreateMessage( channel, System->scratch1, ",i", value ); 00872 break; 00873 } 00874 00875 return CONTROLLER_OK; 00876 } 00877 00878 #endif // OSC
The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.