Model Example
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