- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# system.c

Go to the documentation of this file.

    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.