1+ #ifndef KLIB_1_WIRE_HPP
2+ #define KLIB_1_WIRE_HPP
3+
4+ #include < cstdint>
5+
6+ #include < klib/klib.hpp>
7+ #include < klib/multispan.hpp>
8+ #include < klib/delay.hpp>
9+
10+ namespace klib ::io {
11+ /* *
12+ * @brief A basic 1 wire implementation
13+ *
14+ * @tparam Pin
15+ */
16+ template <typename Pin, typename OneShotTimer>
17+ class wire_1 {
18+ protected:
19+ /* *
20+ * @brief Start a oneshot timer with a specific delay
21+ *
22+ * @param microseconds
23+ */
24+ static void delay_start (const uint32_t microseconds) {
25+ // start the oneshot timer
26+ OneShotTimer::init (nullptr , 1'000'000 / microseconds);
27+ OneShotTimer::enable ();
28+ }
29+
30+ /* *
31+ * @brief Helper function to start a oneshot timer and
32+ * wait until it is done
33+ *
34+ * @param microseconds
35+ * @return true
36+ * @return false
37+ */
38+ static void delay (const uint32_t microseconds) {
39+ // start the oneshot timer
40+ delay_start (microseconds);
41+
42+ // wait until the timer is done
43+ while (!OneShotTimer::done ()) {
44+ // do nothing
45+ }
46+ }
47+
48+ /* *
49+ * @brief Read a single bit on the 1-wire bus
50+ *
51+ * @return true
52+ * @return false
53+ */
54+ static bool read_bit () {
55+ // disable all interrupts
56+ target::disable_irq ();
57+
58+ // set the pin low
59+ Pin::template set<false >();
60+
61+ // when writing we need to send a 1 - 15 microseconds low
62+ // pulse on the bus. If the device wants to send a '1' it
63+ // does nothing. If the device wants to send a '0' the
64+ // device pulls the data line to ground for 60 microseconds
65+ delay (3 );
66+
67+ // set the pin to high (in open drain mode it doesnt
68+ // stops pulling the pin low)
69+ Pin::template set<true >();
70+
71+ // start a one shot timer for 10 microseconds
72+ delay (10 );
73+
74+ // get the state
75+ const bool bit = Pin::get ();
76+
77+ // disable all interrupts
78+ target::enable_irq ();
79+
80+ // start a one shot timer for 53 microseconds
81+ delay (52 );
82+
83+ // return the bit we just read
84+ return bit;
85+ }
86+
87+ /* *
88+ * @brief Write a single bit on the 1-wire bus
89+ *
90+ * @param bit
91+ */
92+ static void write_bit (bool bit) {
93+ // disable all interrupts
94+ target::disable_irq ();
95+
96+ // set the pin low
97+ Pin::template set<false >();
98+
99+ // start a oneshot timer. A '1' needs a 1 - 15 microseconds
100+ // low pulse. A '0' has needs a 60 microseconds low pulse.
101+ //
102+ // The device reads the the data line about 30 microseconds
103+ // after the falling edge. Due to inexpencive timers in the
104+ // device the timing can be off.
105+ delay (bit ? 10 : 60 );
106+
107+ // set the pin to high (in open drain mode it doesnt
108+ // stops pulling the pin low)
109+ Pin::template set<true >();
110+
111+ // disable all interrupts
112+ target::enable_irq ();
113+
114+ // start a one shot timer for 55 or 5 microseconds
115+ // based on if the bit is set or not
116+ delay (bit ? 55 : 5 );
117+ }
118+
119+ public:
120+ /* *
121+ * @brief Init the bus and count the amount of devices on the bus
122+ *
123+ * @return uint32_t
124+ */
125+ static uint32_t init () {
126+ // reset the bus.
127+ reset ();
128+
129+ // amount of devices we found
130+ uint32_t count = 0 ;
131+
132+ // Wait for
133+ for (uint32_t i = 0 ; i < 8 ; i++) {
134+ // start a timer to check if we have
135+ delay (10 );
136+
137+ // check if the pin is low
138+ if (Pin::get ()) {
139+ continue ;
140+ }
141+
142+ // increment the amount of devices
143+ // we have found
144+ count++;
145+
146+ // reset the index
147+ i = 0 ;
148+
149+ // start a timer to wait for a maximum
150+ // of 60 microseconds
151+ delay_start (65 );
152+
153+ // wait until the pin is high again (or
154+ // until the timeout has reached)
155+ while (!Pin::get () && !OneShotTimer::done ()) {
156+ // wait and do nothing
157+ }
158+ }
159+
160+ // return the count
161+ return count;
162+ }
163+
164+ /* *
165+ * @brief Reset the 1-wire bus
166+ *
167+ */
168+ static void reset () {
169+ // disable all interrupts
170+ target::disable_irq ();
171+
172+ // set the pin low
173+ Pin::template set<false >();
174+
175+ // start a one shot timer for at least to 480
176+ // microseconds to reset all the devices on the
177+ // bus. Every device will pull the bus low for
178+ // at least 60 microseconds
179+ delay (500 );
180+
181+ // set the pin to high (in open drain mode it doesnt
182+ // stops pulling the pin low)
183+ Pin::template set<true >();
184+
185+ // disable all interrupts
186+ target::enable_irq ();
187+ }
188+
189+ /* *
190+ * @brief Read a array of bytes from the 1-wire bus
191+ *
192+ * @param data
193+ */
194+ static void read (std::span<uint8_t > data) {
195+ for (uint32_t i = 0 ; i < data.size (); i++) {
196+ uint8_t bits = 0 ;
197+
198+ // read all the bits
199+ for (uint32_t j = 0 ; j < 8 ; j++) {
200+ // read a bit
201+ const bool b = read_bit ();
202+
203+ // set the bits
204+ bits <<= 1 ;
205+ bits |= b;
206+ }
207+
208+ data[i] = bits;
209+ }
210+ }
211+
212+ /* *
213+ * @brief Write a array of bytes from the 1-wire bus
214+ *
215+ * @param data
216+ */
217+ static void write (std::span<const uint8_t > data) {
218+ for (uint32_t i = 0 ; i < data.size (); i++) {
219+ const uint8_t bits = data[i];
220+
221+ // write all the bits
222+ for (uint32_t j = 0 ; j < 8 ; j++) {
223+ write_bit ((bits >> j) & 0x1 );
224+ }
225+ }
226+ }
227+ };
228+ }
229+
230+ #endif
0 commit comments