/*                                              -*- mode:C++; fill-column:100 -*-
  SFBTicker.cpp -  Simple 'where do the usec go?' profiling
  Copyright (C) 2008 The Regents of the University of New Mexico.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  USA
*/

#include "SFBTicker.h"
#include "SFBAssert.h"          // For API_ASSERT_MAX
#include "SFBAlarm.h"          // For Alarms

SFBTicker Ticker IN_BODYRAM;

void SFBTicker::reset(u32 intoState) {
  API_ASSERT_MAX(intoState,MAX_TICKERS);
  u32 now = micros();
  stack = 0;
  push(intoState);
  startUsec = now;
  for (u32 i = 0; i < MAX_TICKERS; ++i) {
    totalUsec[i] = 0;
    enterUsec[i] = now;
  }
}

u32 SFBTicker::getUsec(u32 code) {
  API_ASSERT_MAX(code,MAX_TICKERS);
  return Ticker.totalUsec[code];
}

SFBProfile Profile;

void updateProfile(u32 when, void * arg) {
  SFBProfile * l = (SFBProfile*) arg;
  l->update(when);
}

void SFBProfile::update(u32 when) {

  for (u32 i = 0; i < MAX_TICKERS; ++i) 
    totalMsec[i] += Ticker.getUsec(i)/1000;
  totalTime += Ticker.getTotalUsec()/1000;

  Ticker.reset(TICKER_ALARM_HANDLER);

  Alarms.set(alarmNumber,when+1000*60*30); // Rerun every half hour
}

u32 SFBProfile::getMsec(u32 TickerCode) {
  u32 split = Ticker.getUsec(TickerCode); // Also checks arg validity
  return totalMsec[TickerCode] + split/1000;
}

u32 SFBProfile::getTotalMsec() { 
  return totalTime + Ticker.getTotalUsec()/1000; 
}

u32 SFBProfile::getPPM(u32 TickerCode) {
  const u64 oneMillion = 1000000; // About 20 bits worth
  return (u32) ((oneMillion*getMsec(TickerCode))/getTotalMsec());
}

void SFBProfile::begin() {
  if (alarmNumber == 0) 
    alarmNumber = Alarms.create(updateProfile,this);

  Ticker.reset();

  totalTime = 0;
  for (u32 i = 0; i < MAX_TICKERS; ++i)
    totalMsec[i] = 0;

  Alarms.set(alarmNumber,millis());
}

void SFBProfile::end() {
  if (alarmNumber != 0) 
    Alarms.cancel(alarmNumber);
}
