-
Notifications
You must be signed in to change notification settings - Fork 0
/
hdmi_dev.h
101 lines (91 loc) · 3.81 KB
/
hdmi_dev.h
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
//! \file hdmi_dev.h
//! \brief Commands to interact with the HDMI Peripheral
//!
//! There is only one HDMI peripheral in existence - it is necessarily a
//! singleton. The methods here control that single peripheral.
//!
//! Note that these methods are not reentrant nor thread-safe.
#pragma once
#include "hdmi_fb.h"
#include <stdbool.h>
#include <stdint.h>
//! \brief Initialize the HDMI Peripheral
//!
//! This method flashes the peripheral onto the PL. It also configures the
//! clocks and allocates memory for the framebuffer. If this method fails, the
//! PL and the clocks will be in an undefined state, but no resources will be
//! leaked.
//!
//! \return Whether initialization was successful
bool hdmi_dev_open(void);
//! \brief Inverse of `hdmi_dev_open`
//!
//! This method frees all the host-side resources currently in use by the
//! peripheral. However, it leaves the PL and the clocks in the same state.
//!
//! Additionally, this method signals that the device should stop if it's still
//! running. However, it does not wait for the peripheral to signal that it's
//! idle. If you need that, call `hdmi_dev_stop` first.
void hdmi_dev_close(void);
//! \brief Set the HDMI Peripheral running
//!
//! This function will start running the device in continuous mode. So, it will
//! continuously be reading from the framebuffer and displaying that.
//!
//! This method should be called after the device is opened. It is a no-op if
//! it's not.
void hdmi_dev_start(void);
//! \brief Inverse of `hdmi_dev_start`
//!
//! Again, if this method is called when the HDMI Peripheral is not open, it is
//! a no-op. It also waits for the peripheral to signal that it's idle.
void hdmi_dev_stop(void);
//! \brief Like `hdmi_dev_stop`, but don't wait for the HDMI Peripheral to be
//! idle
void hdmi_dev_stopnow(void);
//! \brief Type for frame ids reported by the HDMI Peripheral
//!
//! These values are represented as `size_t`s, but they play by special rules.
//! They are always unsigned integers, but they don't span the full 32-bit
//! range. They are also relative - it only makes sense to ask for the delta
//! between two sufficiently close frame ids.
//!
//! \see hdmi_fid_delta
typedef uint_fast16_t hdmi_fid_t;
//! \brief Computes the difference between two frame ids
//!
//! These frame ids have to be "close enough". Currently, that means the two
//! frame ids differ by no more than 2048 frames.
//!
//! \return How many frames elapsed from `initial` to `final`
static inline int_fast16_t hdmi_fid_delta(hdmi_fid_t final,
hdmi_fid_t initial) {
// Subtract the two values modulo 2**12, then sign extend to 16-bit
// See: https://stackoverflow.com/a/17719010
int_fast16_t d = (final - initial) & 0xfffu;
int_fast16_t m = 1u << 11;
return (d ^ m) - m;
}
//! \brief Coordinates for pixels serialized by the HDMI Peripheral
//!
//! The device returns these coordinates to tell us where it is on the current
//! frame, and which frame it's on. The row and column are absolute, and they
//! range over [0, 525) and [0, 800) respectively. The frame id is relative. We
//! can subtract two frame ids to see how many frames have elapsed, but there is
//! no zero point.
typedef struct hdmi_coordinate_t {
hdmi_fid_t fid;
uint_fast16_t row;
uint_fast16_t col;
} hdmi_coordinate_t;
//! \brief Get the current coordinate the HDMI Peripheral is serializing
//!
//! The result is only valid if the device has been started. Otherwise, this
//! method just returns garbage.
hdmi_coordinate_t hdmi_dev_coordinate(void);
//! \brief Set the HDMI Peripheral to read from the specified framebuffer
//!
//! The device will use the data inside the framebuffer's data region for the
//! next frame. This will not flush the framebuffer from the cache, so make sure
//! to do that first.
void hdmi_dev_set_fb(hdmi_fb_handle_t *fb);