summaryrefslogtreecommitdiffstats
path: root/app/pll.c
blob: 4b891437133f0b881648b0fa5921e93829c818be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "project.h"

#define JUMP_THRESH 0.1
#define JUMP_TICKS  30
#define FEEDBACK    0.001


static int64_t offset;
static int64_t phase;
static int64_t freq = HZ;

static int out_of_lock = JUMP_TICKS + 1;

uint64_t pll_last_update;
int pll_valid = 0;



static void modify_freq (uint64_t now, int d)
{
  int64_t pd1, pd2, te;

  pd1 = now - phase;

  te = pd1 / freq;
  pd1 %= freq;

  if (d > 0)
    freq += d;
  else
    freq -= -d;


  pd2 = pd1 + (te * freq);

  phase = now - pd2;
}

void pll_dispatch (uint64_t edge)
{
  double f;
  int64_t pd;

  {
    int diff, hf;

    pd = edge - phase;
    pd %= freq;

    hf = (int) (freq >> 1);

    diff = (int) pd;

    if (diff > hf)
      diff = diff - (int) freq;


    f = (double) diff;
    f /= (double) freq;
  }

  if ((f > (JUMP_THRESH)) || (f < - (JUMP_THRESH)))
    out_of_lock++;
  else
    out_of_lock = 0;

#if 0
  printf ("PLL pd %.3f freq %d phase %d\r\n", (float) f, (int) freq, (int) phase);
#endif

  if (out_of_lock > JUMP_TICKS) {
    phase += pd;
    out_of_lock = 0;
    printf ("PLL - jumping\r\n");
    freq = HZ;
  } else {

    f *= FEEDBACK;
    f *= (double) freq;

    modify_freq (edge, (int) f);

  }

  pll_last_update = edge;
}



void pll_set_offset (EPOCH epoch, uint64_t abs)
{
  /* Find nearest second to abs*/
  abs += freq >> 2;
  abs -= phase;
  abs /= freq;

  offset = epoch.s - abs;

  pll_valid = 1;
}




EPOCH pll_decompose (uint64_t abs)
{
  EPOCH ret;

  abs -= phase;

  ret.s = abs / freq;
  abs -= freq * ret.s;


  ret.s += offset;

  abs *= (uint64_t) 1000000000;
  abs = abs / freq;

  ret.ns = abs;

  return ret;
}