Applikationens navn: BOXMove

Gruppemedlemmer: Jakob Vest, Mikkel Andersen, Kenneth Christensen og Erik Monsen

Video af applikationen: http://www.youtube.com/watch?v=fHFWhmiOjZY

 

Wearable projekt

Vi har i vores projekt for wearables valgt, med udgangspunkt i en sensortag, og lave en bokse applikation. Bokse appen skal afmåle ens slag og afgøre om de bliver udført korrekt. Hertil har vi lavet en 3D model og udprint til sensortaggen som gør det muligt og holde på sensortaggen med en sammenknyttet hånd og lave de pågældende slag. Ens slag kan så aflæses på en iPad som er tilsluttet sensortaggen via bluetooth. Det skal siges at dette er en foreløbig prototype og derfor fungerer alt ikke helt optimalt, men prototypen afspejler fint hvordan applikationen skal fungerer i praksis.

Begrundelsen for at vælge denne type applikation ligger i Sensortaggens egenskaber. I og med at sensortaggen skulle opkobles til en iPad, var det oplagt at udnytte dens styrker, som f.eks. muligheden for at give brugeren direkte visuel feedback. Det var derfor også mere interessant at udnytte sensorer, som målte hurtige bevægelser frem for målinger over en periode, som f.eks. temperaturskift. Med dette som udgangspunkt faldt fokus hurtigt på sportsgrene med hurtige bevægelser. Efter at have diskuteret forskellige sportsgrene, blev det besluttet at lave en applikation til boksetræning, da det involvere de sensorer, som har med bevægelser at gøre, samt at Sensortaggens form er oplagt til at holde i sin hånd.

Bokse applikation iPad bokse app ipad 2

 

Opbygning af applikationen og 3D model:

Applikationen tager udgangspunkt i et eksempel som http://www.ti.com/ har lagt ud for sensortag. Eksemplet fra ti.com er skrevet i Objective-C i programmet xcode til IOS og skal ligges over på en iPad. Når eksemplet er lagt over viser det sensortaggens forskellige afmålinger af dets sensorer (accelerometer, gyroskop, magnetometer osv) og fremviser dem løbende på iPaden. Vi valgte og bygge videre på dette eksempel da vi i gruppen ikke er bekendt med IOS programmering og skulle have noget vi hurtigt kunne komme i gang med.

Vi brugte meget tid på opsætningen af iPaden og en apple account for at få kode eksemplet oppe og kører. Da vi havde fået eksemplet oppe forsøgte vi at ændre lidt småting for at se hvad der var muligt. Herunder opsatte vi en if statement så baggrundsfarven skiftede på applikationen når x værdien for accelerometeret kommer over en hvis værdi. For at få accelerometeret op på en værdi som var høj nok var vi nød til at slå rimelig hurtigt/hårdt og dette medførte til ideen af bokse applikationen, men for at applikationen kunne registrerer slagene var vi nød til at have en hurtig update hastighed på sensorer. Dette medførte en række problemer og benspænd da det som udgangspunkt ikke er muligt og ændre update hastigheden på andet en accelerometeret og magnetometer. Derfor var vi begrænset til kun og benytte dem, selvom sensortaggen har andre sensorer som kunne være nyttige herunder dets gyroscop. Da vi havde brugt noget tid på at få afklaret hvilke sensorer der skulle benyttes og fået dem korrekt opsat, kunne vi gå i gang med at afmåle x, y og z værdier for accelerometeret og magnetometer når man lavede forskellige bokseslag. Derfor valgte vi på skift og lave nogle slag med sensortaggen for så at aflæse og analyserer dataene bagefter. Vi fandt ud af at der var meget forskellige udsving i hvor x, y og z lå afhænging af hvem der slog med sensortaggen.  Derfor var vi nød til at lave en stor fejlmargin for hvert slag og inddrage færre x, y og z værdier for hvert slag (vi gør eksempelvis ikke brug af særlig mange af magnetometers værdier). Da de forskellige slag var på plads kunne vi bruge den efterfølgende tid feedback, der end til videre kun fremvist en rød baggrundsfarve. Dette tog dog ikke så lang tid og vi fik hurtig sat det ind i applikationen at den skulle skifte til forskellige farver, ændre teksten og billedet for hvert slag. Det sidste vi noget i projektet før deadline var at fintune slagene, så vi fik vores underviser til at prøve at slå nogle og slagene, og kunne se der igen var problemer med x, y og z værdier, derfor rettede vi dem yderligere til.

Vi har til sensortaggen lavet en 3D model af et håndtag, som vi har tegnet i blender og fået udprintet i en 3D printer. Håndtaget skal fungerer som en slags holder til sensortaggen, så man kan holde den sikkert med en knyttet hånd når man udfører de forskellige slag. 3D modellen er lavet som en aflang cylinder med masse og plads til at en stor hånd kan knytte sig om, samtidig med den ikke er for stor til at hånden kan knytte helt sammen om den. Derudover har 3D modellen et hult rum indeni hvor sensortaggen kan ligge sikkert i med et tilhørende låg. Endelig har 3D modellen et lille hul ind til sluk tænd knappen, så man kan tænde sensortaggen uden at pille den ud af håndtaget. For at man kan se hvordan håndtaget skal vende har vi ude i den ene ende tegnet 2 pile. Den ene pil skal være rettet mod bagsiden af din hånd, og den anden pil skal pege fremad, den samme som peger mod sluk/tænd knappen.

bokse app billede af 3d model bokse app - 3d - 3bokse app - 3d - 2 bokse app - 3d - 1

 

Sensortag og dets sensorer

SensorTag indeholder følgende sensorer:

  • Infrarød temperatursensor
  • Luftfugtighedssensor
  • Lufttrykssensor
  • Accelerometer
  • Magnetometer

http://processors.wiki.ti.com/index.php/Simplelink_SensorTag

For at kunne detekterer boksebevægelserne, har vi benyttet os af sensortaggens accelerometer og magnetometer. Accelerometeret måler op til 8g’s acceleration på tre akser og magnetometeret måles ud fra lokale magnet felter. Sensortaggen har også et gyroskop der havde været velegnet til at detekterer ens bevægelser, men på nuværende tidspunkt kan vi ikke ændre dens update period i vores program. Dette skal gøres på selve sensortaggen og dens firmware. En langsom update period ville skabe en langsom registrering af ens bevægelse, og som gyroskopet er sat op nu opdateres den cirka en gang i sekundet.

Både accelerometeret og magnetometeret anvendes i dette projekt. Deres formål ligger i at aflæse brugerens bevægelser og på den måde afgøre hvilket slag der udføres. Oprindeligt er sensortaggens opdateringshastighed for accelerometeret og magnetometeret, sat til 1 sekund, men efter at have testet de forskellige sensorer, viste det sig at en opdateringshastighed på et 100 ms var optimalt, hvilket i modsætning til gyroskopet var muligt.

boxmove -sensortagside2boxmove -sensortagside1

 

Sensortaggens opførsel

I flowdiagrammet, ses de indledende stadier der er påkrævet for starte BOXMove-applikationen, samt de stadier der findes inden i selv BOXMove-applikationen. For hvert af BOXMove’s stadier, påkræves nogle betingelser, som skal opfyldes inden de eksekveres. Disse er fundet gennem tests af forskellige personers slag. Derudover ses det at sensortaggen returneres til sit begyndelsesstadie, hvis den holdes i ro i fire sekunder.

boxmove -flowdiagram3

Udfordringer:

Under opsætning at sensortag til iPad har der været forskellige udfordringer med opsætning af iPad og developer account, som er nødvendigt for at kunne køre et xcode program på en iPad. Dette var nødvendigt og gøre sammen med vores underviser da vi I gruppen ikke har forskellige administrator rettigheder. Da vores underviser tid var begrænset gik der noget tid før vi kunne komme i gang med udvikling af applikationen til sensortaggen.

 

Hardware udfordringer

Der har generelt i projektet ikke fremkommet nogen større hardware problemer, men vi har oplevet enkelte uregelmæssigheder med sensortag data. Dette mindre problem blev vi opmærksom på da vi begyndte og aflæse dataene for x, y, og z værdierne for accelerometer. Vi udførte en test en 10-15 gange og oplevede en enkelt gang at dataene var forkerte for accelerometer. Vi kunne se at de var forkerte da værdierne var konstante selvom vi lavede mange forskellige bevægelser med accelerometer, som burde have giver forskellige udsving. Dette problem var dog en sjældenhed, og for at løse det genstartede vi programmet og slukkede/tændte sensortaggen, herefter var problemet væk.

 

Software udfordringer:

Der har i projektet været en del udfordringer i at arbejder med Objective-C som vi ikke har arbejder før. Derfor har det været tidskrævende og lære at aflæse det nye sprog og tilføje ny kode stykker i programmet. Dette blev ikke lettere af at vi skulle arbejde på en mac computer da vi primært kun har erfaringer med Windows. Endelig har der også været problemer med det eksisterende kode fra ti.com som vi benyttede som udgangspunkt for projektet. Det kode eksempel som ti.com har liggende tilgængelig gør det muligt og ændre update period for accelerometer og magnetometer på sensortaggen, men det var ikke muligt og ændre update period for gyroskopet. For at ændre dens update period skal man gøre det på firmware for sensortaggen, hvilket var for besværligt og derfor var vi nød til at undlade gyroskopet.

Gennemgang af koden:

I deviceCellTemplate.h

opretter vi Outtekst som en UILabel (hvor vi kan skrive diverse tekst, eksempelvis ”uppercut”, ”RightCross” osv) og opretter accIcon2 som en UIImageView (hvor vi kan smide diverse billeder i eksempelvis et billede af et uppercut eller et Rightcorss)

I deviceCellTemplate.m opsætter vi hvordan teksten i Outtekst skal ligge og hvordan teksten skal se ud samt baggrundsfarven. Og for accIcon2 indsætter vi et billedet (white.jpg) og sætter dets størrelse.

Så giver vi Outtekst og accIcon2 et subview og i layoutSubviews bestemmer vi hvor Outtekst og accIcon2 skal ligge henne og hvilken størrelse deres layout skal have.

I sensorTagApplicationViewController.m indsætter vi 4 if statement I

if([characteristic.UUIDisEqual:[CBUUIDUUIDWithString:[self.d.setupDatavalueForKey:@”Accelerometer data UUID”]]])

Hvor outtekst og accIcon2 skal skifte deres indehold afhænger af hvilken if statement der bliver kørt. For hver af disse if statement er der nogle parametre som skal gøre sig gældende eksempelvis skal der for et uppercut slag gøre sig gældende af accelerometerens y værdi skal være over 0 og z værdien skal være over 1.0 mens magnetometers y værdi skal være over 0. Hertil vil billede i accIcon2 så skifte til et uppercut billede og der vil ligeledes indsættes teksten ”Uppercut” i outtekst og baggrundsfarven skifter til rød og counter værdien sættes til 0.

counter er en variable vi har oprettet i klassen SensorTagApplicationViewController og som udgangspunkt er sat lig med 0, men vi har sat counter++ sådan at counter hele tiden ligger en til sin værdi hver gang

if([characteristic.UUIDisEqual:[CBUUIDUUIDWithString:[self.d.setupDatavalueForKey:@”Accelerometer data UUID”]]]) bliver kørt.

Derudover har vi i SensorTagApplicationViewController ud kommenteret alle de andre sensorer på nær accelerometeret og magnetometeret, da der ikke er nogen grund til at de fremvises i vores applikation når de ikke benyttes til noget.

For at kunne kalde magnetometeret x,y og z værdi i accelerometerets har vi deklareret som globale variabler.

Endelig har vi i SensorTagApplicationViewController sat NSInteger period = 100 for accelerometeret og magnetometeret for at deres sensorer opdaterer med 100 ms

// deviceCellTemplate.h

#import <UIKit/UIKit.h>

#define IPHONE_LANDSCAPE_WIDTH 548.0
#define IPHONE_PORTRAIT_WIDTH 300.0
#define IPAD_LANDSCAPE_WIDTH 934.0
#define IPAD_PORTRAIT_WIDTH 678.0
#define WIDTH_CHECKER (IPHONE_LANDSCAPE_WIDTH + 1.0)

@interface deviceCellTemplate : UITableViewCell {
    UILabel *deviceName;
    UILabel *deviceInfo;
    UIImageView *deviceIcon;
}

@property (nonatomic,retain) UILabel *deviceName;
@property (nonatomic,retain) UILabel *deviceInfo;
@property (nonatomic,retain) UIImageView *deviceIcon;

@end

@interface serviceWithoutPeriodCellTemplate : UITableViewCell {
    UILabel *serviceName;
    UISwitch *serviceOnOffButton;
    int height;
}

@property (nonatomic,retain) UILabel *serviceName;
@property (nonatomic,retain) UISwitch *serviceOnOffButton;
@property int height;

@end

@interface serviceWithPeriodCellTemplate : UITableViewCell {
    UILabel *serviceName;
    UISwitch *serviceOnOffButton;
    UISlider *servicePeriodSlider;
    UILabel *servicePeriodMax;
    UILabel *servicePeriodMin;
    UILabel *servicePeriodCur;
    int height;
}

@property (nonatomic,retain) UILabel *serviceName;
@property (nonatomic,retain) UISwitch *serviceOnOffButton;
@property (nonatomic,retain) UISlider *servicePeriodSlider;
@property (nonatomic,retain) UILabel *servicePeriodMax;
@property (nonatomic,retain) UILabel *servicePeriodMin;
@property (nonatomic,retain) UILabel *servicePeriodCur;
@property int height;

-(IBAction)updateSliderValue:(id)sender;

@end

@interface temperatureCellTemplate : UITableViewCell {
    UILabel *temperatureLabel;
    UIImageView *temperatureIcon;
    UILabel *temperature;
    UIProgressView *temperatureGraph;
    int height;
    UIView *temperatureGraphHolder;
}

@property (nonatomic,retain) UILabel *temperatureLabel;
@property (nonatomic,retain) UIImageView *temperatureIcon;
@property (nonatomic,retain) UILabel *temperature;
@property (nonatomic,retain) UIProgressView *temperatureGraph;
@property (nonatomic,retain)UIView *temperatureGraphHolder;

@property int height;
@end

@interface accelerometerCellTemplate : UITableViewCell {
    UILabel *accLabel;
    UIImageView *accIcon;
    UIImageView *accIcon2;
    UILabel *accValueX;
    UILabel *accValueY;
    UILabel *accValueZ;
    UILabel *outtekst;
    UIProgressView *accGraphX;
    UIProgressView *accGraphY;
    UIProgressView *accGraphZ;
    UIView *accGraphHolder;
    UIButton *accCalibrateButton;
    int height;

}

@property (nonatomic,retain) UILabel *accLabel;
@property (nonatomic,retain) UIImageView *accIcon;
@property (nonatomic,retain) UIImageView *accIcon2;
@property (nonatomic,retain) UILabel *accValueX;
@property (nonatomic,retain) UILabel *accValueY;
@property (nonatomic,retain) UILabel *accValueZ;
@property (nonatomic,retain) UILabel *outtekst;
@property (nonatomic,retain) UIProgressView *accGraphX;
@property (nonatomic,retain) UIProgressView *accGraphY;
@property (nonatomic,retain) UIProgressView *accGraphZ;
@property (nonatomic,retain) UIView *accGraphHolder;
@property (nonatomic,retain) UIButton *accCalibrateButton;
@property int height;

@end
//deviceCellTemplate.m

#import "deviceCellTemplate.h"

@implementation deviceCellTemplate

@synthesize deviceName,deviceInfo,deviceIcon;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {

        self.backgroundColor = [UIColor whiteColor];
        self.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;

        // Initialization code
        self.deviceName = [[UILabel alloc] init];
        self.deviceName.textAlignment = NSTextAlignmentLeft;
        self.deviceName.font = [UIFont boldSystemFontOfSize:14];

        self.deviceInfo = [[UILabel alloc] init];
        self.deviceInfo.textAlignment = NSTextAlignmentLeft;
        self.deviceInfo.font = [UIFont boldSystemFontOfSize:8];

        self.deviceIcon = [[UIImageView alloc] init];
        [self.deviceIcon setAutoresizingMask:UIViewAutoresizingNone];
        self.deviceIcon.contentMode = UIViewContentModeScaleAspectFit;

        [self.contentView addSubview:self.deviceName];
        [self.contentView addSubview:self.deviceInfo];
        [self.contentView addSubview:self.deviceIcon];

    }
    return self;
}

-(void)layoutSubviews {
    [super layoutSubviews];
    CGRect contentRect = self.contentView.bounds;
    CGFloat boundsX = contentRect.origin.x;
    CGRect fr;

    fr = CGRectMake(boundsX + 10, 2, 45, 45);
    self.deviceIcon.frame = fr;

    fr = CGRectMake(boundsX + 70, 5, self.contentView.bounds.size.width - 100, 25);
    self.deviceName.frame = fr;

    fr = CGRectMake(boundsX + 70, 30,self.contentView.bounds.size.width - 100, 15);
    self.deviceInfo.frame = fr;

}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

@end

@implementation serviceWithoutPeriodCellTemplate

@synthesize serviceName;
@synthesize serviceOnOffButton;
@synthesize height;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        self.height = 50;
        self.serviceName = [[UILabel alloc] init];
        self.serviceName.textAlignment = NSTextAlignmentLeft;
        self.serviceName.font = [UIFont boldSystemFontOfSize:17];
        self.serviceName.backgroundColor = [UIColor clearColor];

        self.serviceOnOffButton = [[UISwitch alloc] init];
        self.serviceOnOffButton.enabled = YES;
        self.serviceOnOffButton.hidden = NO;

        [self.contentView addSubview:self.serviceOnOffButton];
        [self.contentView addSubview:self.serviceName];
    }
    return self;
}

-(void) layoutSubviews {
    [super layoutSubviews];
    CGRect contentRect = self.contentView.bounds;
    CGFloat boundsX = contentRect.origin.x;
    CGRect fr;

    if (contentRect.size.width < WIDTH_CHECKER) {
        self.serviceName.font = [UIFont boldSystemFontOfSize:12];
        fr = CGRectMake(boundsX + 10, 10, 300, 30);
        self.serviceName.frame = fr;
    }
    else {
        self.serviceName.font = [UIFont boldSystemFontOfSize:17];
        fr = CGRectMake(boundsX + 10, 10, 300, 30);
        self.serviceName.frame = fr;
    }
    fr = CGRectMake(boundsX + contentRect.size.width - 90, 10, 100, 30);
    self.serviceOnOffButton.frame = fr;

}

@end

@implementation serviceWithPeriodCellTemplate

@synthesize serviceName;
@synthesize serviceOnOffButton;
@synthesize servicePeriodSlider;
@synthesize servicePeriodMax;
@synthesize servicePeriodMin;
@synthesize servicePeriodCur;
@synthesize height;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        self.height = 100;
        self.serviceName = [[UILabel alloc] init];
        self.serviceName.textAlignment = NSTextAlignmentLeft;
        self.serviceName.font = [UIFont boldSystemFontOfSize:17];
        self.serviceName.backgroundColor = [UIColor clearColor];

        self.serviceOnOffButton = [[UISwitch alloc] init];
        self.serviceOnOffButton.enabled = YES;
        self.serviceOnOffButton.hidden = NO;

        self.servicePeriodSlider = [[UISlider alloc] init];
        self.servicePeriodSlider.enabled = YES;
        self.servicePeriodSlider.hidden = NO;
        [self.servicePeriodSlider addTarget:self action:@selector(updateSliderValue:) forControlEvents:UIControlEventValueChanged];

        self.servicePeriodMax = [[UILabel alloc] init];
        self.servicePeriodMax.textAlignment = NSTextAlignmentLeft;
        self.servicePeriodMax.font = [UIFont systemFontOfSize:16];
        self.servicePeriodMax.backgroundColor = [UIColor clearColor];

        self.servicePeriodMin = [[UILabel alloc] init];
        self.servicePeriodMin.textAlignment = NSTextAlignmentLeft;
        self.servicePeriodMin.font = [UIFont systemFontOfSize:16];
        self.servicePeriodMin.backgroundColor = [UIColor clearColor];

        self.servicePeriodCur = [[UILabel alloc] init];
        self.servicePeriodCur.textAlignment = NSTextAlignmentLeft;
        self.servicePeriodCur.font = [UIFont systemFontOfSize:16];
        self.servicePeriodCur.backgroundColor = [UIColor clearColor];

        [self.contentView addSubview:self.serviceOnOffButton];
        [self.contentView addSubview:self.serviceName];
        [self.contentView addSubview:self.servicePeriodSlider];
        [self.contentView addSubview:self.servicePeriodMax];
        [self.contentView addSubview:self.servicePeriodMin];
        [self.contentView addSubview:self.servicePeriodCur];

    }
    return self;
}

-(void) layoutSubviews {
    [super layoutSubviews];
    CGRect contentRect = self.contentView.bounds;
    CGFloat boundsX = contentRect.origin.x;
    CGRect fr;
    NSLog(@"Frame : %f,%f,%f,%f ",contentRect.origin.x,contentRect.origin.y,contentRect.size.width,contentRect.size.height);
    if (self.contentView.bounds.size.width < WIDTH_CHECKER) self.height = 100;
    else self.height = 50;

    if (contentRect.size.width < WIDTH_CHECKER) {
        fr = CGRectMake(boundsX + 10, 10, 300, 30);
        self.serviceName.frame = fr;

        fr = CGRectMake(boundsX + contentRect.size.width - 90, 10, 100, 30);
        self.serviceOnOffButton.frame = fr;

        fr = CGRectMake(boundsX + (contentRect.size.width / 2) - 80, 63, 160, 30);
        self.servicePeriodSlider.frame = fr;

        fr = CGRectMake(boundsX + (contentRect.size.width / 2) - 130, 63, 160, 30);
        self.servicePeriodMin.frame = fr;

        fr = CGRectMake(boundsX + (contentRect.size.width / 2) + 90, 63, 160, 30);
        self.servicePeriodMax.frame = fr;

        fr = CGRectMake(boundsX + (contentRect.size.width / 2) - 30, 40, 160, 30);
        self.servicePeriodCur.frame = fr;
    }
    else {
        fr = CGRectMake(boundsX + 10, 10, 300, 30);
        self.serviceName.frame = fr;

        fr = CGRectMake(boundsX + contentRect.size.width - 90, 10, 100, 30);
        self.serviceOnOffButton.frame = fr;

        fr = CGRectMake(boundsX + (contentRect.size.width / 2) - 80, 3, 160, 30);
        self.servicePeriodSlider.frame = fr;

        fr = CGRectMake(boundsX + (contentRect.size.width / 2) - 130, 3, 160, 30);
        self.servicePeriodMin.frame = fr;

        fr = CGRectMake(boundsX + (contentRect.size.width / 2) + 90, 3, 160, 30);
        self.servicePeriodMax.frame = fr;

        fr = CGRectMake(boundsX + (contentRect.size.width / 2) - 30, 25, 160, 30);
        self.servicePeriodCur.frame = fr;
    }

}

-(IBAction)updateSliderValue:(id)sender {
    UISlider *slider = (UISlider *)sender;
    self.servicePeriodCur.text = [NSString stringWithFormat: @"%0.0fms",[slider value]];
}

@end

@implementation temperatureCellTemplate

@synthesize temperature,temperatureIcon,temperatureLabel,temperatureGraph,temperatureGraphHolder,height;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {

        self.height = 150;

        // Initialization code
        self.temperatureLabel = [[UILabel alloc] init];
        self.temperatureLabel.textAlignment = NSTextAlignmentLeft;
        self.temperatureLabel.font = [UIFont boldSystemFontOfSize:17];
        self.temperatureLabel.backgroundColor = [UIColor clearColor];

        self.temperature = [[UILabel alloc] init];
        self.temperature.textAlignment = NSTextAlignmentRight;
        self.temperature.font = [UIFont boldSystemFontOfSize:18];
        self.temperature.textColor = [UIColor blackColor];
        self.temperature.backgroundColor = [UIColor clearColor];

        self.temperatureIcon = [[UIImageView alloc] init];
        self.temperatureIcon.image = [UIImage imageNamed:@"temperature.png"];
        [self.temperatureIcon setAutoresizingMask:UIViewAutoresizingNone];
        self.temperatureIcon.contentMode = UIViewContentModeScaleAspectFit;

        self.temperatureGraph = [[UIProgressView alloc] initWithFrame:CGRectMake(30, 0, 100, 8)];
        self.temperatureGraph.progress = 1.0f;
        self.temperatureGraph.transform = CGAffineTransformRotate(self.temperatureGraph.transform, -M_PI/2.0);
        self.temperatureGraph.progressTintColor = [UIColor blueColor];
        self.temperatureGraphHolder = [[UIView alloc] init];
        [self.temperatureGraphHolder addSubview:self.temperatureGraph];

        [self.contentView addSubview:self.temperatureLabel];
        [self.contentView addSubview:self.temperature];
        [self.contentView addSubview:self.temperatureIcon];
        [self.contentView addSubview:self.temperatureGraphHolder];

    }
    return self;
}

-(void)layoutSubviews {
    [super layoutSubviews];
    CGRect contentRect = self.contentView.bounds;
    CGFloat boundsX = contentRect.origin.x;
    CGRect fr;

    if (contentRect.size.width < WIDTH_CHECKER) {
        fr = CGRectMake(boundsX + 5, 25, 70, 100);
        self.temperatureIcon.frame = fr;

        fr = CGRectMake(boundsX, 5, self.contentView.bounds.size.width, 25);
        self.temperatureLabel.textAlignment = NSTextAlignmentCenter;
        self.temperatureLabel.frame = fr;

        fr = CGRectMake(boundsX + self.contentView.bounds.size.width - 5, 61,-100, 25);
        self.temperature.frame = fr;

        fr = CGRectMake((contentRect.origin.x + (contentRect.size.width / 2 ) - 75), 80,95,50);
        self.temperatureGraphHolder.frame = fr;
    }
    else {
        fr = CGRectMake(boundsX + 5, 25, 70, 100);
        self.temperatureIcon.frame = fr;

        fr = CGRectMake(boundsX + 80, 60, self.contentView.bounds.size.width - 100, 25);
        self.temperatureLabel.frame = fr;

        fr = CGRectMake(boundsX + self.contentView.bounds.size.width - 5, 61,-100, 25);
        self.temperature.frame = fr;

        fr = CGRectMake(boundsX + self.contentView.bounds.size.width - 250, 75,100,50);
        self.temperatureGraphHolder.frame = fr;
    }
}

@end

@implementation accelerometerCellTemplate

@synthesize accLabel,accIcon,accIcon2,accValueX,accValueY,accValueZ,outtekst,accGraphX,accGraphY,accGraphZ,accGraphHolder,accCalibrateButton,height;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {

        self.height = 500;
        self.backgroundColor = [UIColor greenColor];

        // Initialization code
        self.accLabel = [[UILabel alloc] init];
        self.accLabel.textAlignment = NSTextAlignmentLeft;
        self.accLabel.font = [UIFont boldSystemFontOfSize:17];
        self.accLabel.backgroundColor = [UIColor clearColor];

        self.accIcon = [[UIImageView alloc] init];
        self.accIcon.image = [UIImage imageNamed:@"accelerometer.png"];
        [self.accIcon setAutoresizingMask:UIViewAutoresizingNone];
        self.accIcon.contentMode = UIViewContentModeScaleAspectFit;

        //nyt billede indsat
        self.accIcon2 = [[UIImageView alloc] init];
        self.accIcon2.image = [UIImage imageNamed:@"white.jpg"];
        [self.accIcon2 setAutoresizingMask:UIViewAutoresizingNone];
        self.accIcon2.contentMode = UIViewContentModeScaleAspectFit;

        self.accValueX = [[UILabel alloc] init];
        self.accValueX.textAlignment = NSTextAlignmentRight;
        self.accValueX.font = [UIFont boldSystemFontOfSize:17];
        self.accValueX.backgroundColor = [UIColor clearColor];

        self.accValueY = [[UILabel alloc] init];
        self.accValueY.textAlignment = NSTextAlignmentRight;
        self.accValueY.font = [UIFont boldSystemFontOfSize:17];
        self.accValueY.backgroundColor = [UIColor clearColor];

        self.accValueZ = [[UILabel alloc] init];
        self.accValueZ.textAlignment = NSTextAlignmentRight;
        self.accValueZ.font = [UIFont boldSystemFontOfSize:17];
        self.accValueZ.backgroundColor = [UIColor clearColor];

        //tekst
        self.outtekst = [[UILabel alloc] init];
        self.outtekst.textAlignment = NSTextAlignmentLeft;
        self.outtekst.font = [UIFont boldSystemFontOfSize:20];
        self.outtekst.backgroundColor = [UIColor clearColor];

        self.accGraphX = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, 100, 8)];
        self.accGraphX.progress = 1.0f;
        self.accGraphX.transform = CGAffineTransformRotate(self.accGraphX.transform, -M_PI/2.0);
        self.accGraphX.progressTintColor = [UIColor blueColor];

        self.accGraphY = [[UIProgressView alloc] initWithFrame:CGRectMake(30, 0, 100, 8)];
        self.accGraphY.progress = 1.0f;
        self.accGraphY.transform = CGAffineTransformRotate(self.accGraphY.transform, -M_PI/2.0);
        self.accGraphY.progressTintColor = [UIColor greenColor];

        self.accGraphZ = [[UIProgressView alloc] initWithFrame:CGRectMake(60, 0, 100, 8)];
        self.accGraphZ.progress = 1.0f;
        self.accGraphZ.transform = CGAffineTransformRotate(self.accGraphZ.transform, -M_PI/2.0);
        self.accGraphZ.progressTintColor = [UIColor redColor];

        self.accGraphHolder = [[UIView alloc] init];
        [self.accGraphHolder addSubview:self.accGraphX];
        [self.accGraphHolder addSubview:self.accGraphY];
        [self.accGraphHolder addSubview:self.accGraphZ];
        UILabel *legendX = [[UILabel alloc] initWithFrame:CGRectMake(45, 60, 15, 15)];
        legendX.text = @"X";
        legendX.backgroundColor = [UIColor clearColor];
        [self.accGraphHolder addSubview:legendX];
        UILabel *legendY = [[UILabel alloc] initWithFrame:CGRectMake(75, 60, 15, 15)];
        legendY.text = @"Y";
        legendY.backgroundColor = [UIColor clearColor];
        [self.accGraphHolder addSubview:legendY];
        UILabel *legendZ = [[UILabel alloc] initWithFrame:CGRectMake(105, 60, 15, 15)];
        legendZ.text = @"Z";
        legendZ.backgroundColor = [UIColor clearColor];
        [self.accGraphHolder addSubview:legendZ];

        self.accCalibrateButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [self.accCalibrateButton setTitle:@"Calibrate" forState:UIControlStateNormal];

        [self.contentView addSubview:self.accLabel];
        [self.contentView addSubview:self.accIcon];
        [self.contentView addSubview:self.accIcon2];
        [self.contentView addSubview:self.accValueX];
        [self.contentView addSubview:self.accValueY];
        [self.contentView addSubview:self.accValueZ];
        [self.contentView addSubview:self.accGraphHolder];
        [self.contentView addSubview:self.accCalibrateButton];
        [self.contentView addSubview:self.outtekst];

    }
    return self;
}

-(void)layoutSubviews {
    [super layoutSubviews];
    CGRect contentRect = self.contentView.bounds;
    CGRect fr;

    if (self.contentView.bounds.size.width < WIDTH_CHECKER) self.height = 500;
    else self.height = 500;

    if (contentRect.size.width < WIDTH_CHECKER) {

        fr = CGRectMake(contentRect.origin.x + 5, 55, 70, 100);
        self.accIcon.frame = fr;

        fr = CGRectMake(contentRect.origin.x + 5, 200, 70, 100);
        self.accIcon2.frame = fr;

        fr = CGRectMake(contentRect.origin.x, 5, self.contentView.bounds.size.width, 25);
        self.accLabel.textAlignment = NSTextAlignmentCenter;
        self.accLabel.frame = fr;

        fr = CGRectMake(contentRect.origin.x + self.contentView.bounds.size.width - 5, 61, -100, 25);
        self.accValueX.frame = fr;
        fr.origin.y += 35;
        self.accValueY.frame = fr;
        fr.origin.y += 35;
        self.accValueZ.frame = fr;

        fr = CGRectMake(contentRect.origin.x + self.contentView.bounds.size.width - 5, 61, -100, 25);
        self.outtekst.frame = fr;
        fr.origin.y += 35;

        fr = CGRectMake((contentRect.origin.x + (contentRect.size.width / 2 ) - 75), 85,95,50);
        self.accGraphHolder.frame = fr;

        fr = CGRectMake(contentRect.origin.x + (self.contentView.bounds.size.width / 2) - 65,170,150,35);
        self.accCalibrateButton.frame = fr;

    }
    else {
        fr = CGRectMake(contentRect.origin.x + 5, 25, 70, 100);
        self.accIcon.frame = fr;

        fr = CGRectMake(contentRect.origin.x + 50, 300, 100, 150);
        self.accIcon2.frame = fr;

        fr = CGRectMake(contentRect.origin.x + 80, 60, self.contentView.bounds.size.width - 100, 25);
        self.accLabel.frame = fr;

        fr = CGRectMake(contentRect.origin.x + self.contentView.bounds.size.width - 5, 21, -100, 25);
        self.accValueX.frame = fr;
        fr.origin.y += 40;
        self.accValueY.frame = fr;
        fr.origin.y += 40;
        self.accValueZ.frame = fr;
        fr.origin.y += 40;
        self.outtekst.frame = fr;

        fr = CGRectMake(contentRect.origin.x + self.contentView.bounds.size.width - 250, 60,100,50);
        self.accGraphHolder.frame = fr;

        fr = CGRectMake(contentRect.origin.x + self.contentView.bounds.size.width - 400,65,150,35);
        self.accCalibrateButton.frame = fr;

    }

}

@end
//SensorTagApplicationViewController
#import "SensorTagApplicationViewController.h"

@interface SensorTagApplicationViewController ()

@end

@implementation SensorTagApplicationViewController

@synthesize d;
@synthesize ambientTemp;
@synthesize sensorsEnabled;
int counter = 1;

float macx = 0;
float macy = 0;
float macz = 0;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

-(id) initWithStyle:(UITableViewStyle)style andSensorTag:(BLEDevice *)andSensorTag {
    self = [super initWithStyle:style];
    if (self) {

        self.d = andSensorTag;
        /*
        if (!self.ambientTemp){
            self.ambientTemp = [[temperatureCellTemplate alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Ambient temperature"];
            self.ambientTemp.temperatureIcon.image = [UIImage imageNamed:@"temperature.png"];
            self.ambientTemp.temperatureLabel.text = @"Ambient Temperature";
            self.ambientTemp.temperature.text = @"-.-°C";
        }
        if (!self.irTemp) {
            self.irTemp = [[temperatureCellTemplate alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"IR temperature"];
            self.irTemp.temperatureIcon.image = [UIImage imageNamed:@"objecttemperature.png"];
            self.irTemp.temperatureLabel.text = @"Object Temperature";
            self.irTemp.temperature.text = @"-.-°C";
        }
         */

        if (!self.acc) {
            self.acc = [[accelerometerCellTemplate alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Accelerometer"];
            self.acc.accLabel.text = @"Accelerometer";
            self.acc.accValueX.text = @"-";
            self.acc.accValueY.text = @"-";
            self.acc.accValueZ.text = @"-";
            self.acc.accCalibrateButton.hidden = YES;

        }
        /*
        if (!self.rH) {
            self.rH = [[temperatureCellTemplate alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Relative humidity"];
            self.rH.temperatureIcon.image = [UIImage imageNamed:@"relativehumidity.png"];
            self.rH.temperatureLabel.text = @"Relative humidity";
            self.rH.temperature.text = @"-%rH";
        }
         */

        if (!self.mag) {
            self.mag = [[accelerometerCellTemplate alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Magnetometer"];
            self.mag.accLabel.text = @"Magnetometer";
            self.mag.accIcon.image = [UIImage imageNamed:@"magnetometer.png"];
            self.mag.accValueX.text = @"-";
            self.mag.accValueY.text = @"-";
            self.mag.accValueZ.text = @"-";
            [self.mag.accCalibrateButton addTarget:self action:@selector(handleCalibrateMag) forControlEvents:UIControlEventTouchUpInside];
            self.magSensor = [[sensorMAG3110 alloc] init];
        }
        /*
        if (!self.baro) {
            self.baro = [[temperatureCellTemplate alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Barometer"];
            self.baro.temperatureLabel.text = @"Barometer";
            self.baro.temperatureIcon.image = [UIImage imageNamed:@"barometer.png"];
            self.baro.temperature.text = @"1000mBar";
        }

        if (!self.gyro) {
            self.gyro = [[accelerometerCellTemplate alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Gyroscope"];
            self.gyro.accLabel.text = @"Gyroscope";
            self.gyro.accIcon.image = [UIImage imageNamed:@"gyroscope.png"];
            self.gyro.accValueX.text = @"-";
            self.gyro.accValueY.text = @"-";
            self.gyro.accValueZ.text = @"-";
            [self.gyro.accCalibrateButton addTarget:self action:@selector(handleCalibrateGyro) forControlEvents:UIControlEventTouchUpInside];
            self.gyroSensor = [[sensorIMU3000 alloc] init];

        }
         */

    }
    [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(alphaFader:) userInfo:nil repeats:YES];

    self.currentVal = [[sensorTagValues alloc]init];
    self.vals = [[NSMutableArray alloc]init];

    self.logInterval = 0.2; //1000 ms

    self.logTimer = [NSTimer scheduledTimerWithTimeInterval:self.logInterval target:self selector:@selector(logValues:) userInfo:nil repeats:YES];

    return self;
}

- (void)viewDidAppear:(BOOL)animated {
    self.sensorsEnabled = [[NSMutableArray alloc] init];
    if (!self.d.p.isConnected) {
        self.d.manager.delegate = self;
        [self.d.manager connectPeripheral:self.d.p options:nil];
    }
    else {
        self.d.p.delegate = self;
        [self configureSensorTag];
        self.title = @"TI BLE Sensor Tag application";
    }
}

-(void)viewWillDisappear:(BOOL)animated {
    [self deconfigureSensorTag];

}

-(void)viewDidDisappear:(BOOL)animated {
    self.sensorsEnabled = nil;
    self.d.manager.delegate = nil;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;

    UIBarButtonItem *mailer = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCompose target:self action:@selector(sendMail:)];

    [self.navigationItem setRightBarButtonItem:mailer];

}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellType = [self.sensorsEnabled objectAtIndex:indexPath.row];

    if ([cellType isEqualToString:@"Ambient temperature"]) return self.ambientTemp.height;
    if ([cellType isEqualToString:@"IR temperature"]) return self.irTemp.height;
    if ([cellType isEqualToString:@"Accelerometer"]) return self.acc.height;
    if ([cellType isEqualToString:@"Humidity"]) return self.rH.height;
    if ([cellType isEqualToString:@"Magnetometer"]) return self.mag.height;
    if ([cellType isEqualToString:@"Barometer"]) return self.baro.height;
    if ([cellType isEqualToString:@"Gyroscope"]) return self.gyro.height;

    return 50;
}

-(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (section == 0) {
        return @"Sensors";
    }
    return @"";
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return self.sensorsEnabled.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellType = [self.sensorsEnabled objectAtIndex:indexPath.row];

    if ([cellType isEqualToString:@"Ambient temperature"]) {

        return self.ambientTemp;
    }
    else if ([cellType isEqualToString:@"IR temperature"]) {
        return self.irTemp;
    }
    else if ([cellType isEqualToString:@"Accelerometer"]) {
        return self.acc;
    }
    else if ([cellType isEqualToString:@"Humidity"]) {
        return self.rH;
    }
    else if ([cellType isEqualToString:@"Barometer"]) {
        return self.baro;
    }
    else if ([cellType isEqualToString:@"Gyroscope"]) {
        return self.gyro;
    }
    else if ([cellType isEqualToString:@"Magnetometer"]) {
        return self.mag;
    }

    // Something has gone wrong, because we should never get here, return empty cell
    return [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Unkown Cell"];
}

/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the specified item to be editable.
    return YES;
}
*/

/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    }   
    else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }   
}
*/

/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/

/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the item to be re-orderable.
    return YES;
}
*/

#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

}

-(void) configureSensorTag {
    // Configure sensortag, turning on Sensors and setting update period for sensors etc ...
    /*
    if (([self sensorEnabled:@"Ambient temperature active"]) || ([self sensorEnabled:@"IR temperature active"])) {
        // Enable Temperature sensor
        CBUUID *sUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"IR temperature service UUID"]];
        CBUUID *cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"IR temperature config UUID"]];
        uint8_t data = 0x01;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"IR temperature data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:YES];

        if ([self sensorEnabled:@"Ambient temperature active"]) [self.sensorsEnabled addObject:@"Ambient temperature"];
        if ([self sensorEnabled:@"IR temperature active"]) [self.sensorsEnabled addObject:@"IR temperature"];

    }
     */

    if ([self sensorEnabled:@"Accelerometer active"]) {
        CBUUID *sUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Accelerometer service UUID"]];
        CBUUID *cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Accelerometer config UUID"]];
        CBUUID *pUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Accelerometer period UUID"]];
        NSInteger period = 100; //[[self.d.setupData valueForKey:@"Accelerometer period"] integerValue];
        uint8_t periodData = (uint8_t)(period / 10);
        NSLog(@"%d",periodData);
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:pUUID data:[NSData dataWithBytes:&periodData length:1]];
        uint8_t data = 0x01;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Accelerometer data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:YES];
        [self.sensorsEnabled addObject:@"Accelerometer"];
    }
    /*
    if ([self sensorEnabled:@"Humidity active"]) {
        CBUUID *sUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Humidity service UUID"]];
        CBUUID *cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Humidity config UUID"]];
        uint8_t data = 0x01;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Humidity data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:YES];
        [self.sensorsEnabled addObject:@"Humidity"];
    }

    if ([self sensorEnabled:@"Barometer active"]) {
        CBUUID *sUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer service UUID"]];
        CBUUID *cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer config UUID"]];
        //Issue calibration to the device 
        uint8_t data = 0x02;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:YES];

        cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer calibration UUID"]];
        [BLEUtility readCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID];
        [self.sensorsEnabled addObject:@"Barometer"];
    }

    if ([self sensorEnabled:@"Gyroscope active"]) {
        CBUUID *sUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Gyroscope service UUID"]];
        CBUUID *cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Gyroscope config UUID"]];
        uint8_t data = 0x07;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Gyroscope data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:YES];
        [self.sensorsEnabled addObject:@"Gyroscope"];
    }
    */
    if ([self sensorEnabled:@"Magnetometer active"]) {
        CBUUID *sUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Magnetometer service UUID"]];
        CBUUID *cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Magnetometer config UUID"]];
        CBUUID *pUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Magnetometer period UUID"]];
        NSInteger period = 100; //[[self.d.setupData valueForKey:@"Magnetometer period"] integerValue];
        uint8_t periodData = (uint8_t)(period / 10);
        NSLog(@"%d",periodData);
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:pUUID data:[NSData dataWithBytes:&periodData length:1]];
        uint8_t data = 0x01;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Magnetometer data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:YES];
        [self.sensorsEnabled addObject:@"Magnetometer"];
    }

}

-(void) deconfigureSensorTag {
    /*
    if (([self sensorEnabled:@"Ambient temperature active"]) || ([self sensorEnabled:@"IR temperature active"])) {
        // Enable Temperature sensor
        CBUUID *sUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"IR temperature service UUID"]];
        CBUUID *cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"IR temperature config UUID"]];
        unsigned char data = 0x00;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"IR temperature data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:NO];
    }
     */
    if ([self sensorEnabled:@"Accelerometer active"]) {
        CBUUID *sUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Accelerometer service UUID"]];
        CBUUID *cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Accelerometer config UUID"]];
        uint8_t data = 0x00;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Accelerometer data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:NO];
    }
    /*
    if ([self sensorEnabled:@"Humidity active"]) {
        CBUUID *sUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Humidity service UUID"]];
        CBUUID *cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Humidity config UUID"]];
        uint8_t data = 0x00;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Humidity data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:NO];
    }
     */

    if ([self sensorEnabled:@"Magnetometer active"]) {
        CBUUID *sUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Magnetometer service UUID"]];
        CBUUID *cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Magnetometer config UUID"]];
        uint8_t data = 0x00;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Magnetometer data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:NO];
    }
     /*
    if ([self sensorEnabled:@"Gyroscope active"]) {
        CBUUID *sUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Gyroscope service UUID"]];
        CBUUID *cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Gyroscope config UUID"]];
        uint8_t data = 0x00;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Gyroscope data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:NO];
    }

    if ([self sensorEnabled:@"Barometer active"]) {
        CBUUID *sUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer service UUID"]];
        CBUUID *cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer config UUID"]];
        //Disable sensor
        uint8_t data = 0x00;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];
        cUUID =  [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer data UUID"]];
        [BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:NO];

    }
     */
}

-(bool)sensorEnabled:(NSString *)Sensor {
    NSString *val = [self.d.setupData valueForKey:Sensor];
    if (val) {
        if ([val isEqualToString:@"1"]) return TRUE;
    }
    return FALSE;
}

-(int)sensorPeriod:(NSString *)Sensor {
    NSString *val = [self.d.setupData valueForKey:Sensor];
    return [val integerValue];
}

#pragma mark - CBCentralManager delegate function 

-(void) centralManagerDidUpdateState:(CBCentralManager *)central {

}

-(void) centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    peripheral.delegate = self;
    [peripheral discoverServices:nil];
}

#pragma mark - CBperipheral delegate functions

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    NSLog(@"..");
    if ([service.UUID isEqual:[CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Gyroscope service UUID"]]]) {
        [self configureSensorTag];
    }
}

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    NSLog(@".");
    for (CBService *s in peripheral.services) [peripheral discoverCharacteristics:nil forService:s];
}

-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSLog(@"didUpdateNotificationStateForCharacteristic %@, error = %@",characteristic.UUID, error);
}

-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    //NSLog(@"didUpdateValueForCharacteristic = %@",characteristic.UUID);

    /*
    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:[self.d.setupData valueForKey:@"IR temperature data UUID"]]]) {
        float tAmb = [sensorTMP006 calcTAmb:characteristic.value];
        float tObj = [sensorTMP006 calcTObj:characteristic.value];

        self.ambientTemp.temperature.text = [NSString stringWithFormat:@"%.1f°C",tAmb];
        self.ambientTemp.temperature.textColor = [UIColor blackColor];
        self.ambientTemp.temperatureGraph.progress = (tAmb / 100.0) + 0.5;
        self.irTemp.temperature.text = [NSString stringWithFormat:@"%.1f°C",tObj];
        self.irTemp.temperatureGraph.progress = (tObj / 1000.0) + 0.5;
        self.irTemp.temperature.textColor = [UIColor blackColor];

        self.currentVal.tAmb = tAmb;
        self.currentVal.tIR = tObj;

    }
     */

    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Accelerometer data UUID"]]]) {
        float x = [sensorKXTJ9 calcXValue:characteristic.value];
        float y = [sensorKXTJ9 calcYValue:characteristic.value];
        float z = [sensorKXTJ9 calcZValue:characteristic.value];

        self.acc.accValueX.text = [NSString stringWithFormat:@"X: % 0.1fG",x];
        self.acc.accValueY.text = [NSString stringWithFormat:@"Y: % 0.1fG",y];
        self.acc.accValueZ.text = [NSString stringWithFormat:@"Z: % 0.1fG",z];

        self.acc.accValueX.textColor = [UIColor blackColor];
        self.acc.accValueY.textColor = [UIColor blackColor];
        self.acc.accValueZ.textColor = [UIColor blackColor];

        self.acc.accGraphX.progress = (x / [sensorKXTJ9 getRange]) + 0.5;
        self.acc.accGraphY.progress = (y / [sensorKXTJ9 getRange]) + 0.5;
        self.acc.accGraphZ.progress = (z / [sensorKXTJ9 getRange]) + 0.5;

        self.currentVal.accX = x;
        self.currentVal.accY = y;
        self.currentVal.accZ = z;

        //NSLog(@"Counter vaerdien %i", counter);

        //NSLog(@"% 0.1f,% 0.1f,% 0.1f,% 0.1f,% 0.1f,% 0.1f", macx,macy,macz,x,y,z);

        counter++;

        //self.acc.backgroundColor  = [UIColor greenColor];

        /*
        if (x > 0.4) {
            self.acc.backgroundColor  = [UIColor redColor];
        }
        */

        //NSLog(@"Your message here - here");

        /*
        if (x > 0.4 && x < 1) {
        self.acc.outtekst.text = [NSString stringWithFormat:@"Hårdt"];
            NSLog(@"hårdtttt");
            //NSLog(@"x vaerdi for x % 0.1f", x);
            self.acc.accIcon2.image = [UIImage imageNamed:@"mikk2.png"];
        }
         */

        if (y > 0 && z > 1.0 && macy > 0) {
            self.acc.outtekst.text = [NSString stringWithFormat:@"Uppercut"];
            NSLog(@"uppercut");
            self.acc.accIcon2.image = [UIImage imageNamed:@"Uppercut.jpg"];
            self.acc.backgroundColor  = [UIColor redColor];
            counter = 0;
        }

        if (x > 0.3 && z < 0.4 && y < 0.8) {
            self.acc.outtekst.text = [NSString stringWithFormat:@"RightCross"];
            NSLog(@"RightCross");
            self.acc.accIcon2.image = [UIImage imageNamed:@"RightCross.jpg"];
            self.acc.backgroundColor  = [UIColor yellowColor];
            counter = 0;
        }

        if (x > 1.0 && y > 0.3) {
            self.acc.outtekst.text = [NSString stringWithFormat:@"Hook"];
            NSLog(@"Hook");
            self.acc.accIcon2.image = [UIImage imageNamed:@"Hook.jpg"];
            self.acc.backgroundColor  = [UIColor blueColor];
            counter = 0;
        }

        if (x < 0.4 && y < 0.2 && z < 0.3 && counter >= 40) {
            self.acc.outtekst.text = [NSString stringWithFormat:@" "];
            self.acc.backgroundColor  = [UIColor greenColor];
            self.acc.accIcon2.image = [UIImage imageNamed:@"white.jpg"];
        }

    }
    /*
    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Humidity data UUID"]]]) {

        float rHVal = [sensorSHT21 calcPress:characteristic.value];
        self.rH.temperature.text = [NSString stringWithFormat:@"%0.1f%%rH",rHVal];
        self.rH.temperatureGraph.progress = (rHVal / 100);
        self.rH.temperature.textColor = [UIColor blackColor];

        self.currentVal.humidity = rHVal;

    }
     */

    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Magnetometer data UUID"]]]) {

        float x = [self.magSensor calcXValue:characteristic.value];
        float y = [self.magSensor calcYValue:characteristic.value];
        float z = [self.magSensor calcZValue:characteristic.value];

        macx =x;
        macy =y;
        macz =z;

        self.mag.accValueX.text = [NSString stringWithFormat:@"X: % 0.1fuT",x];
        self.mag.accValueY.text = [NSString stringWithFormat:@"Y: % 0.1fuT",y];
        self.mag.accValueZ.text = [NSString stringWithFormat:@"Z: % 0.1fuT",z];

        self.mag.accValueX.textColor = [UIColor blackColor];
        self.mag.accValueY.textColor = [UIColor blackColor];
        self.mag.accValueZ.textColor = [UIColor blackColor];

        self.mag.accGraphX.progress = (x / [sensorMAG3110 getRange]) + 0.5;
        self.mag.accGraphY.progress = (y / [sensorMAG3110 getRange]) + 0.5;
        self.mag.accGraphZ.progress = (z / [sensorMAG3110 getRange]) + 0.5;

        self.currentVal.magX = x;
        self.currentVal.magY = y;
        self.currentVal.magZ = z;

    }
    /*

    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer calibration UUID"]]]) {

        self.baroSensor = [[sensorC953A alloc] initWithCalibrationData:characteristic.value];

        CBUUID *sUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer service UUID"]];
        CBUUID *cUUID = [CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer config UUID"]];
        //Issue normal operation to the device
        uint8_t data = 0x01;
        [BLEUtility writeCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:&data length:1]];

    }

    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Barometer data UUID"]]]) {
        int pressure = [self.baroSensor calcPressure:characteristic.value];
        self.baro.temperature.text = [NSString stringWithFormat:@"%d mBar",pressure];
        self.baro.temperatureGraph.progress = ((float)((float)pressure - (float)800) / (float)400);
        self.baro.temperature.textColor = [UIColor blackColor];

        self.currentVal.press = pressure;

    }

    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:[self.d.setupData valueForKey:@"Gyroscope data UUID"]]]) {

        float x = [self.gyroSensor calcXValue:characteristic.value];
        float y = [self.gyroSensor calcYValue:characteristic.value];
        float z = [self.gyroSensor calcZValue:characteristic.value];

        self.gyro.accValueX.text = [NSString stringWithFormat:@"X: % 0.1f°/S",x];
        self.gyro.accValueY.text = [NSString stringWithFormat:@"Y: % 0.1f°/S",y];
        self.gyro.accValueZ.text = [NSString stringWithFormat:@"Z: % 0.1f°/S",z];

        self.gyro.accValueX.textColor = [UIColor blackColor];
        self.gyro.accValueY.textColor = [UIColor blackColor];
        self.gyro.accValueZ.textColor = [UIColor blackColor];

        self.gyro.accGraphX.progress = (x / [sensorIMU3000 getRange]) + 0.5;
        self.gyro.accGraphY.progress = (y / [sensorIMU3000 getRange]) + 0.5;
        self.gyro.accGraphZ.progress = (z / [sensorIMU3000 getRange]) + 0.5;

        self.currentVal.gyroX = x;
        self.currentVal.gyroY = y;
        self.currentVal.gyroZ = z;

    }
     */

    [self.tableView reloadData];
}

-(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSLog(@"didWriteValueForCharacteristic %@ error = %@",characteristic.UUID,error);
}

- (IBAction) handleCalibrateMag {
    NSLog(@"Calibrate magnetometer pressed !");
    [self.magSensor calibrate];
}
- (IBAction) handleCalibrateGyro {
    NSLog(@"Calibrate gyroscope pressed ! ");
    [self.gyroSensor calibrate];
}

-(void) alphaFader:(NSTimer *)timer {
    CGFloat w,a;
    if (self.ambientTemp) {
        [self.ambientTemp.temperature.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.ambientTemp.temperature.textColor = [self.ambientTemp.temperature.textColor colorWithAlphaComponent:a];
    }
    if (self.irTemp) {
        [self.irTemp.temperature.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.irTemp.temperature.textColor = [self.irTemp.temperature.textColor colorWithAlphaComponent:a];
    }
    if (self.acc) {
        [self.acc.accValueX.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.acc.accValueX.textColor = [self.acc.accValueX.textColor colorWithAlphaComponent:a];

        [self.acc.accValueY.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.acc.accValueY.textColor = [self.acc.accValueY.textColor colorWithAlphaComponent:a];

        [self.acc.accValueZ.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.acc.accValueZ.textColor = [self.acc.accValueZ.textColor colorWithAlphaComponent:a];
    }
    if (self.rH) {
        [self.rH.temperature.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.rH.temperature.textColor = [self.rH.temperature.textColor colorWithAlphaComponent:a];
    }
    if (self.mag) {
        [self.mag.accValueX.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.mag.accValueX.textColor = [self.mag.accValueX.textColor colorWithAlphaComponent:a];

        [self.mag.accValueY.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.mag.accValueY.textColor = [self.mag.accValueY.textColor colorWithAlphaComponent:a];

        [self.mag.accValueZ.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.mag.accValueZ.textColor = [self.mag.accValueZ.textColor colorWithAlphaComponent:a];
    }
    if (self.baro) {
        [self.baro.temperature.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.baro.temperature.textColor = [self.baro.temperature.textColor colorWithAlphaComponent:a];
    }
    if (self.gyro) {
        [self.gyro.accValueX.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.gyro.accValueX.textColor = [self.gyro.accValueX.textColor colorWithAlphaComponent:a];

        [self.gyro.accValueY.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.gyro.accValueY.textColor = [self.gyro.accValueY.textColor colorWithAlphaComponent:a];

        [self.gyro.accValueZ.textColor getWhite:&w alpha:&a];
        if (a > MIN_ALPHA_FADE) a -= ALPHA_FADE_STEP;
        self.gyro.accValueZ.textColor = [self.gyro.accValueZ.textColor colorWithAlphaComponent:a];
    }
}

-(void) logValues:(NSTimer *)timer {
    NSString *date = [NSDateFormatter localizedStringFromDate:[NSDate date]
                                                    dateStyle:NSDateFormatterShortStyle
                                                    timeStyle:NSDateFormatterMediumStyle];
    self.currentVal.timeStamp = date;
    sensorTagValues *newVal = [[sensorTagValues alloc]init];
    newVal.tAmb = self.currentVal.tAmb;
    newVal.tIR = self.currentVal.tIR;
    newVal.accX = self.currentVal.accX;
    newVal.accY = self.currentVal.accY;
    newVal.accZ = self.currentVal.accZ;
    newVal.gyroX = self.currentVal.gyroX;
    newVal.gyroY = self.currentVal.gyroY;
    newVal.gyroZ = self.currentVal.gyroZ;
    newVal.magX = self.currentVal.magX;
    newVal.magY = self.currentVal.magY;
    newVal.magZ = self.currentVal.magZ;
    newVal.press = self.currentVal.press;
    newVal.humidity = self.currentVal.humidity;
    newVal.timeStamp = date;

    [self.vals addObject:newVal];

}

- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
    NSLog(@"Finished with result : %u error : %@",result,error);
    [self dismissViewControllerAnimated:YES completion:nil];
}

-(IBAction)sendMail:(id)sender {
    NSLog(@"Mail button pressed");
    NSMutableString *sensorData = [[NSMutableString alloc] init];
    [sensorData appendString:@"Timestamp,Ambient Temperature,IR Temperature,Accelerometer X-Axis,Accelerometer Y-Axis,Accelerometer Z-Axis,Barometric Pressure,Relative Humidity,Gyroscope X,Gyroscope Y,Gyroscope Z,Magnetometer X, Magnetometer Y, Magnetometer Z\n"];
    for (int ii=0; ii < self.vals.count; ii++) {
        sensorTagValues *s = [self.vals objectAtIndex:ii];
        [sensorData appendFormat:@"%@,%0.1f,%0.1f,%0.2f,%0.2f,%0.2f,%0.0f,%0.1f,%0.1f,%0.1f,%0.1f,%0.1f,%0.1f,%0.1f\n",s.timeStamp,s.tAmb,s.tIR,s.accX,s.accY,s.accZ,s.press,s.humidity,s.gyroX,s.gyroY,s.gyroZ,s.magX,s.magY,s.magZ];
    }

    MFMailComposeViewController *mFMCVC = [[MFMailComposeViewController alloc]init];
    if (mFMCVC) {
        if ([MFMailComposeViewController canSendMail]) {
            mFMCVC.mailComposeDelegate = self;
            [mFMCVC setSubject:@"Data from BLE Sensor"];
            [mFMCVC setMessageBody:@"Data from sensor" isHTML:NO];
            [self presentViewController:mFMCVC animated:YES completion:nil];

            [mFMCVC addAttachmentData:[sensorData dataUsingEncoding:NSUTF8StringEncoding] mimeType:@"text/csv" fileName:@"Log.csv"];
        }
        else {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Mail error" message:@"Device has not been set up to send mail" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alertView show];
        }
    }
}
@end

 

Andre udfordringer:

Vi har oplevet nogle uoverensstemmelser for vores bokse resultater. Når vi aflæste datene for accelerometer og magnetometer fra forskellige testpersoner og deres slag var der en del uoverensstemmelser i dataene. Dette skyldes hver enkelt testperson slår forskelligt, og efter som vi i gruppen ikke er bekendt med den korrekte udførsel af bokse slag, er datene vi har benyttet til at afgør hvilket slag der er hvad (uppercut, hook, osv) været upræcise. Dette har gjort at vi har været nød til at nedskærpe præcisionen.

 

Konklusion:

Vi har formået og få lavet en applikation til sensortag som benytter to af dens sensorer et accelerometer og magnetometer. Applikationen kan registrere når du slår tre forskellige slag uppercut, rightcross, og hook, og giver feedback når slaget er udført. Hertil har vi fået lavet en 3D model et håndtag som man kan holde sikkert i hånden, mens man udføre slagene.

Havde vi haft mere tid til projektet kunne vi have brugt tiden på forbedring af koden/ rydde op i det. Lige nu er der meget overflødig kode som bør fjernes. Derudover kan vi forbedre 3D modellen så den ville passe bedre til en bokse handske. Applikationen genkender de forskellige slag, men det er meget upræcis. Så det er ikke nødvendigt og udfører slagene præcis. Hvis vi skulle komme det problem til livs, skulle vi i projektet have haft kontakt til en erfaring bokser som vi skulle have testet applikationen på.

Vi kunne også have inddraget eksperter (erfarende bokser) i starten af projektet, som en del af en større forundersøgelse hvor vi kunne have set på tilsvarende teknologier til at registrerer slag. Hertil ville vi så have brugt tid på at undersøger hvilke fejl og mangel der eksisterende ved disse produkter, som vi så ville forsøge at undgå i vores produkt.  Hvis vi have haft tilknyttet idrætsfolk og professionelle bokser i starten af projektet kunne vi også have set på hvilke karakteristika der er ved hvert bokseslag og hvordan hele kroppen benyttes til hvert slag og ikke kun armen. Endelig ville vi også via eksperter kunne se om det virkelig er muligt at registrerer ens slag helt korrekt.

 

Andet

Se hjemmeside for eksisterende eksempel vi tog udgangspunkt: http://www.ti.com/tool/sensortag-sw

Leave a Reply