16fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org/*
26fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org * Copyright (C) 2012 The Android Open Source Project
36fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org *
46fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org * Licensed under the Apache License, Version 2.0 (the "License");
56fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org * you may not use this file except in compliance with the License.
66fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org * You may obtain a copy of the License at
76fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org *
86fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org *      http://www.apache.org/licenses/LICENSE-2.0
96fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org *
106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org * Unless required by applicable law or agreed to in writing, software
116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org * distributed under the License is distributed on an "AS IS" BASIS,
126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org * See the License for the specific language governing permissions and
146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org * limitations under the License.
153f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org */
163f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org
173f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org#define __STDC_LIMIT_MACROS
183f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org
193f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org#define LOG_TAG "common_time"
203f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org#include <utils/Log.h>
213f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org
223f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org#include <stdint.h>
233f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org
243f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org#include <utils/Errors.h>
253f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org#include <utils/LinearTransform.h>
263f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org
273f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org#include "common_clock.h"
283f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org
293f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.orgnamespace android {
303f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org
316fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgCommonClock::CommonClock() {
326fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_slew_        = 0;
336fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_valid_ = false;
343f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org
356fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_.a_zero = 0;
366fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_.b_zero = 0;
376fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_.a_to_b_numer = local_to_common_freq_numer_ = 1;
386fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_.a_to_b_denom = local_to_common_freq_denom_ = 1;
396fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    duration_trans_ = cur_trans_;
406fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org}
416fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
426fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgbool CommonClock::init(uint64_t local_freq) {
436fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    Mutex::Autolock lock(&lock_);
446fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
456fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    if (!local_freq)
466fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        return false;
476fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
486fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    uint64_t numer = kCommonFreq;
496fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    uint64_t denom = local_freq;
506fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
516fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    LinearTransform::reduce(&numer, &denom);
526fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    if ((numer > UINT32_MAX) || (denom > UINT32_MAX)) {
536fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        ALOGE("Overflow in CommonClock::init while trying to reduce %lld/%lld",
546fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org             kCommonFreq, local_freq);
556fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        return false;
566fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    }
573f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org
586fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_.a_to_b_numer = local_to_common_freq_numer_ =
596fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        static_cast<uint32_t>(numer);
603f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org    cur_trans_.a_to_b_denom = local_to_common_freq_denom_ =
613f0af3b06425f635f3559f0bd4f53efea95fa5e2johannkoenig@chromium.org        static_cast<uint32_t>(denom);
626fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    duration_trans_ = cur_trans_;
636fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
646fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    return true;
656fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org}
666fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
676fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgstatus_t CommonClock::localToCommon(int64_t local, int64_t *common_out) const {
686fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    Mutex::Autolock lock(&lock_);
696fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
706fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    if (!cur_trans_valid_)
716fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        return INVALID_OPERATION;
726fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
736fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    if (!cur_trans_.doForwardTransform(local, common_out))
746fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        return INVALID_OPERATION;
756fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
766fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    return OK;
776fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org}
786fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
796fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgstatus_t CommonClock::commonToLocal(int64_t common, int64_t *local_out) const {
806fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    Mutex::Autolock lock(&lock_);
816fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
826fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    if (!cur_trans_valid_)
836fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        return INVALID_OPERATION;
846fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
856fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    if (!cur_trans_.doReverseTransform(common, local_out))
866fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        return INVALID_OPERATION;
876fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
886fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    return OK;
896fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org}
906fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
916fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgint64_t CommonClock::localDurationToCommonDuration(int64_t localDur) const {
926fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    int64_t ret;
936fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    duration_trans_.doForwardTransform(localDur, &ret);
946fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    return ret;
956fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org}
966fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
976fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgvoid CommonClock::setBasis(int64_t local, int64_t common) {
986fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    Mutex::Autolock lock(&lock_);
996fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1006fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_.a_zero = local;
1016fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_.b_zero = common;
1026fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_valid_ = true;
1036fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org}
1046fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1056fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgvoid CommonClock::resetBasis() {
1066fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    Mutex::Autolock lock(&lock_);
1076fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1086fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_.a_zero = 0;
1096fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_.b_zero = 0;
1106fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    cur_trans_valid_ = false;
1116fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org}
1126fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1136fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.orgstatus_t CommonClock::setSlew(int64_t change_time, int32_t ppm) {
1146fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    Mutex::Autolock lock(&lock_);
1156fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1166fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    int64_t new_local_basis;
1176fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    int64_t new_common_basis;
1186fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org
1196fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org    if (cur_trans_valid_) {
1206fefe538d859300e7febe78271828198c10f1b52fgalligan@chromium.org        new_local_basis = change_time;
121        if (!cur_trans_.doForwardTransform(change_time, &new_common_basis)) {
122            ALOGE("Overflow when attempting to set slew rate to %d", ppm);
123            return INVALID_OPERATION;
124        }
125    } else {
126        new_local_basis = 0;
127        new_common_basis = 0;
128    }
129
130    cur_slew_ = ppm;
131    uint32_t n1 = local_to_common_freq_numer_;
132    uint32_t n2 = 1000000 + cur_slew_;
133
134    uint32_t d1 = local_to_common_freq_denom_;
135    uint32_t d2 = 1000000;
136
137    // n1/d1 has already been reduced, no need to do so here.
138    LinearTransform::reduce(&n1, &d2);
139    LinearTransform::reduce(&n2, &d1);
140    LinearTransform::reduce(&n2, &d2);
141
142    cur_trans_.a_zero = new_local_basis;
143    cur_trans_.b_zero = new_common_basis;
144    cur_trans_.a_to_b_numer = n1 * n2;
145    cur_trans_.a_to_b_denom = d1 * d2;
146
147    return OK;
148}
149
150}  // namespace android
151