Model Example

 


Here is an example ORCA model object with commentary. It is a part of the CAMAC 811 ADC object. Note that not all of the object code is included here.


* ORAD811Model.cpp

* Orca

*

* Created by Mark Howe on Sat Nov 16 2002.

* Copyright (c) 2002 CENPA, University of Washington. All rights reserved.

*

*/


#pragma mark •••Imported Files

#import "ORAD811Model.h"

#import "StatusLog.h"

#import "ORDataTypeAssigner.h"

#import "ORParamItem.h"

#import "ORDataDescriptionItem.h"

#import "ORHeaderSection.h"

#import "ORDataPacket.h"

#import "ORCamacControllerCard.h"

#import "ORCamacCrateModel.h"


NSString* ORAD811OnlineMaskChangedNotification    = @"ORAD811OnlineMaskChangedNotification";

NSString* ORAD811SettingsLock                     = @"ORAD811SettingsLock";

NSString* ORAD811SuppressZerosChangedNotification = @"ORAD811SuppressZerosChangedNotification";


@implementation ORAD811Model


#pragma mark •••Initialization

- (id) init

{

    self = [super init];

    return self;

}


- (void) dealloc

{

    [super dealloc];

}


- (void) setUpImage

{

    [self setImage:[NSImage imageNamed:@"AD811Card"]];  //Defines the object's icon

}


- (void) makeMainController

{   

    [self linkToController:@"ORAD811Controller"];      //This is the object's controller...i.e. the

                                                       //glue code between the view and the model

}


#pragma mark •••Accessors

- (unsigned long) dataId

{

    return dataId;                                    //Data ids are used to uniquely identify an object's

}                                                     //data record(s). An object will have one data for

- (void) setDataId: (unsigned long) DataId            //record that it will put into the data stream.

{

    dataId = DataId;

}


- (unsigned char)onlineMask {


    return onlineMask;

}


- (void)setOnlineMask:(unsigned char)anOnlineMask

{

    //Setters that are 'undoable' have to register with the undo manager

    [[[self undoManager] prepareWithInvocationTarget:self] setOnlineMask:[self onlineMask]];


    onlineMask = anOnlineMask;


    //Variables that are displayed to the user must post the fact that they have changed.

    //These notifications are picked by the Controller objects that pass the model data

    //on to the view.


    [[NSNotificationCenter defaultCenter]

        postNotificationName:ORAD811OnlineMaskChangedNotification object:self];


}


...

...

...


#pragma mark •••DataTaker


- (void) setDataIds:(id)assigner

{                                                 //This method is called so data taking objects can

    dataId = [assigner assignDataIds:kShortForm]; //assign their data ids. Objects can request to use

}                                                 //the 'short' form but may be assigned the 'long' form,

                                                  //so they must be prepared to deal with either type.

- (void) syncDataIdsWith:(id)anotherCard          //Note that there is only one Data id per object of this

{                                                 //class no matter how many instances there are. Also

    [self setDataId:[anotherCard dataId]];        //note that there would be additional entries in these

}                                                 //methods it this object could produce other data records.





//All objects that need to put an kind of record must have a 'dataRecordDescription' method.

//The resulting info is put in the data header so that the records can be decoded by others.

- (NSDictionary*) dataRecordDescription

{

    NSMutableDictionary* dataDictionary = [NSMutableDictionary dictionary];

    NSDictionary* aDictionary = [NSDictionary dictionaryWithObjectsAndKeys:

        @"ORAD811DecoderForAdc",          @"decoder",

        [NSNumber numberWithLong:dataId], @"dataId",

        [NSNumber numberWithBool:NO],     @"variable",

        [NSNumber numberWithLong:IsShortForm(dataId)?1:2],@"length",

        [NSNumber numberWithBool:YES],    @"canBeGated",

        nil];

    [dataDictionary setObject:aDictionary forKey:@"ADC"];

    return dataDictionary;

}


//At the start of run, all data taking objects receive the 'runTaskStarted' message. It is here that

//hardware initialization and prerun checks are normally done. Also note the the data description

//is added to the data packet at this time.

- (void) runTaskStarted:(ORDataPacket*)aDataPacket userInfo:(id)userInfo

{


    if(![self adapter]){

        [NSException raise:@"Not Connected" format:@"You must connect to a PCI-CAMAC Controller (i.e. a CC32)."];

    }


//----------------------------------------------------------------------------------------

// first add our description to the data description


    [aDataPacket addDataDescriptionItem:[self dataRecordDescription] forKey:@"ORAD811Model"];


//----------------------------------------------------------------------------------------

    controller = [[self adapter] controller]; //cache the controller for alittle bit more speed.

    unChangingDataPart = (([self crateNumber]&0x1e)<<21) | (([self stationNumber]& 0x0000001f)<<16); //doesn't change so do it here.

    cachedStation = [self stationNumber];

    [self clearExceptionCount];



    int i;

    onlineChannelCount = 0;

    for(i=0;i<8;i++){

        if(onlineMask & (0x1<<i)){

            onlineList[onlineChannelCount] = i;

            onlineChannelCount++;

        }

    }



    if([[userInfo objectForKey:@"doinit"]intValue]){

        [self generalReset];

    }

    [self enableLAMEnableLatch];

}


//The 'takeData' is called continuously during the data taking phase of a run. This happens in the

//data taking thread, it is is important to remember that calls made to methods that may also

//be called from other threads must be thread-safe or chaos will ensue.

- (void) takeData:(ORDataPacket*)aDataPacket userInfo:(id)userInfo

{

    NSString* errorLocation;

    BOOL resetDone;

    NS_DURING


        //check the LAM

        unsigned short dummy;

        unsigned short status = [controller camacShortNAF:cachedStation a:12 f:8 data:&dummy];

        if(isQbitSet(status)) { //LAM status comes back in the Q bit

            if(onlineChannelCount){

                resetDone = NO;

                int i;

                for(i=0;i<onlineChannelCount;i++){

                    //read one adc channnel

                    unsigned short adcValue;

                    [controller camacShortNAF:cachedStation a:onlineList[i] f:2 data:&adcValue];

                    if(!(suppressZeros && adcValue==0)){

                        if(IsShortForm(dataId)){

                            unsigned long data = dataId |

                                                 unChangingDataPart |

                                                 (onlineList[i]&0xf)<<12 |

                                                 (adcValue & 0xfff);

                            [aDataPacket addLongsToFrameBuffer:&data length:1];

                        }

                        else {

                            unsigned long data[2];

                            data[0] = dataId | 2;

                            data[1] = unChangingDataPart | (onlineList[i]&0xf)<<12 | (adcValue & 0xfff);

                            [aDataPacket addLongsToFrameBuffer:data length:2];

                        }

                    }

                    if(i == 7) resetDone = YES;

                }

               //read of last channel with this command clears

               if(!resetDone) [controller camacShortNAF:[self stationNumber] a:7 f:2 data:&dummy];

           }

    NS_    }

  HANDLER

        NSLogError(@"",@"AD811 Card Error",errorLocation,nil);

        [self incExceptionCount];

        [localException raise];

    NS_ENDHANDLER

}



//The 'runTaskStopped' method is called end the run has ended. This object does nothing, but in general

//it would be the place to do any hardware shutdown that is required or last minute records inserted into

//the data stream. There is one other method called 'runCloseOut' that is called after

//the run has stopped as a oppertunity after all objects have been notified that the run is stopped.

- (void) runTaskStopped:(ORDataPacket*)aDataPacket userInfo:(id)userInfo

{

}


...

...

...


#pragma mark •••Archival


//Here is where the object stores its persistant data. The data is stored in the configuration file.

- (id)initWithCoder:(NSCoder*)decoder

{

    [self = [super initWithCoder:decoder];

    [[self undoManager] disableUndoRegistration];

    [self setOnlineMask:[decoder decodeIntForKey:@"OR811OnlineMask"]];

    [self setSuppressZeros:[decoder decodeIntForKey:@"OR811SuppressZeros"]];

    [[self undoManager] enableUndoRegistration];

    return self;

}


//Here is where the object read its persistant data back in.

- (void)encodeWithCoder:(NSCoder*)encoder

{

    [super encodeWithCoder:encoder];

    [encoder encodeInt:onlineMask forKey:@"OR811OnlineMask"];

    [encoder encodeInt:suppressZeros forKey:@"OR811SuppressZeros"];

}


//This method is called for records that need to be placed into the data header. Usually that means

//state data that is important for data analysis, i.e. gains, thresholds, etc...

- (NSMutableDictionary*) captureCurrentState:(NSMutableDictionary*)dictionary

{

    [NSMutableDictionary* objDictionary = [super captureCurrentState:dictionary];

    [objDictionary setObject:[NSNumber numberWithInt:onlineMask] forKey:@"onlineMask"];

    [objDictionary setObject:[NSNumber numberWithBool:suppressZeros] forKey:@"suppressZeros"];

    return objDictionary;

}


@end