/
outshift.c
319 lines (283 loc) · 8.32 KB
/
outshift.c
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/*
* This file is part of Raspberry Pi steuert Modelleisenbahn
* Copyright(C) 2008 - 2015 Kurt Zerzawy www.zerzawy.ch
*
* Raspberry Pi steuert Modelleisenbahn is free software:
* you can redistribute it and/or modify it under the terms of the
* GNU General Public Licence as published by the Free Software Foundation,
* either version 3 of the Licence, or (at your option) any later version.
*
* Raspberry Pi steuert Modelleisenbahn 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 GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Raspberry Pi steuert Modelleisenbahn.
* If not, see <http://www.gnu.org/licenses/>.
*
* Spreitenbacher Eisenbahn Amateur Klub SPEAK
* www.speak.li
*/
/**
* \file
* Output shift registers
* \author
* Kurt Zerzawy
*/
/* $Author: Kurt $
* $Date: 2015-08-05 08:06:23 +0200 (Mi, 05 Aug 2015) $
* $Revision: 2537 $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include "log.h"
#include "hw.h" /* needs IO Pins for Shifting functions */
#include "ap216.h"
#include "outshift.h"
/*@null@*/ static struct sRegister * m_pOutshiftReg = NULL; /**< pointer to the first output register */
static unsigned short m_outshiftRegLen = 0; /**< number of outshift registers */
static _Bool m_outshiftEnabled; /**< true if outshift is enabled */
/*@null@*/ static unsigned short * pOutshiftFeedbackRegisters = NULL;
/*@null@*/ static unsigned short * pOutshiftFeedbackOutput = NULL;
static unsigned short outshiftFeedbackRegisterLen = 0;
static _Bool m_todo = true; /**< true if there is work for outshift */
/**
* \author Kurt Zerzawy
*
* diagram of the outshift register
* \verbatim
OutIn <----, ,----< OutOut
| |
| |
,-+--------------+-,
| |<--- OutStrobe
| |<--- OutClock
'--+------------+--'
| .. |
| |
v v
Q31 Q0
\endverbatim
* timing diagram for the shiftout of data.
*
* OutStrobe must be low during shiftout.
*
* positive flange is shifting the data
* \verbatim
-----,-----data----,------
OutOut -----'----valid----'------
,-----------,
OutClock -----------^ '------
\endverbatim
*
* Timing fuer das Ausgeben der Daten an die Treiber
* \verbatim
,-----------,
OutStrobe -------^ '------
\endverbatim
*
* constructor
*
* this function is generating the data structure for the outshift registers
*
* from this moment, you can use the datas. You should call this function as soon
* as you know how many outshift prints exist on your system.
*
* on Bad Waldsee the register constructor is calling this function
* @paranm pRegister pointer to the datastructur of the register, from
* where the outshift registers are fetching the data
* @param registerLen number of outshift registers a 16 Bit. Note: since the
* AP216 has two 16 bit words, it is necessary to give the
* double number of AP216 prints.
* @exception if not enough RAM available, the function calls exit
*/
/*@maynotreturn@*/
void outshift(/*@only@*/ struct sRegister * const pRegister,
/*@in@*/ const unsigned short registerLen)
{
LOG_INF("started");
assert(NULL != pRegister);
if(!pRegister)
{
LOG_ERR("no pointer given");
exit(EXIT_FAILURE);
}
m_pOutshiftReg = pRegister;
m_outshiftRegLen = registerLen;
/* now set all values to 0 */
outshiftInit();
LOG_INF("ended");
}
/**
* destructor
*
* destrois the data structure and releases the ressources.
*
* After callling the destructor, you must not access the outshift registers any more
*/
void outshiftDestroy(void)
{
LOG_INF("started");
m_pOutshiftReg = NULL;
LOG_INF("ended");
}
/**
* initialiser
*
* prepares the outhift registers and resets all registers and outshift registers
*/
void outshiftInit(void)
{
LOG_INF("started");
assert(NULL != m_pOutshiftReg);
ports_init();
/* now set all values to 0 */
memset(m_pOutshiftReg, 0, m_outshiftRegLen * sizeof(unsigned short));
/*VORSICHT, nur TEST */
/* for(i = 0; i < m_outshiftRegLen; i++)
{
ptr->value = 0x5555;
ptr++;
}
*/ outshiftEnable(true);
outshiftRegSend();
LOG_INF("ended");
}
/**
* enables outshifting
*
* with this function, the outshift of data can be anabled or disabled,
* @param enable true allows outshifting,
* false keeps the given data on outputs
*/
void outshiftEnable(_Bool enable)
{
LOG_INF("started");
m_outshiftEnabled = enable;
LOG_INF("ended");
}
/**
* output function
*
* here the internal datas on the registers are shifted out to the hardware.
*
* to do this, 16 Bit wise the datas are shifted out until all datas are on the right place in
* the outshift registers. Then a Strobe pulse is writing the shifted data to the output registers
* where they stay until the next function call.
*
* The information about the number of outshift registers and the location of the internal
* regisers was given during construction of the outshift.
*
* Normally this function is used in the main loop as last instruction.
*/
void outshiftRegSend(void)
{
unsigned short i, j;
unsigned short outputWord = 0;
struct sRegister * ptr = NULL;
assert(NULL != m_pOutshiftReg);
if(! m_outshiftEnabled)
{
// return;
}
if(! m_todo)
{
// return;
}
// LOG_INF("started");
/* initialize for start of shifting out */
/* Strobe low, clock low, data out high */
port_set_out_strobe(true);
port_set_out_clk_0();
port_set_out_out(true);
ptr = m_pOutshiftReg;
for(i = 0; i < m_outshiftRegLen; i++)
{
/* repeat for each register available
* note: this is the double number of the prints
*/
outputWord = ptr->value; /* copy value */
for (j = 0; j < 16; j++)
{
/* repeat for all 16 Bits of a register
* if most significant bit is high, set output
*/
port_set_out_out((outputWord & 0x8000) != 0x8000);
/* note: Datas are given over to UNC20 inversely */
// fprintf(stderr, "%c",((outputWord & 0x8000)) ? '1' : '0');
port_set_out_clk_1(); /* set same time the passiv flange of Clock*/
outputWord <<= 1; /* shift word one left */
waitALittle();
/* set the active flange of Clock */
port_set_out_clk_0();
waitALittle();
}
ptr++;
}
/* now the shifting is over, so make a strobe puls */
port_set_out_strobe(false);
waitALittle();
waitALittle();
waitALittle();
waitALittle();
//nanosleep(& interval, &interval); TODO must have some delay!!
port_set_out_strobe(true);
m_todo = false;
// LOG_INF("ended");
}
void outshiftToDo(void)
{
m_todo = true;
}
/* NOTE: later also dynamic tests on outputs */
void outshiftFeedback(const unsigned short nrRegisters)
{
assert (0 < nrRegisters);
outshiftFeedbackRegisterLen = nrRegisters;
pOutshiftFeedbackOutput = malloc(outshiftFeedbackRegisterLen * sizeof(unsigned short *));
pOutshiftFeedbackRegisters = malloc(outshiftFeedbackRegisterLen * sizeof(unsigned short *));
if(NULL == pOutshiftFeedbackOutput)
{
LOG_ERR("not enough RAM");
exit(EXIT_FAILURE);
}
if(NULL == pOutshiftFeedbackRegisters)
{
LOG_ERR("not enough RAM");
exit(EXIT_FAILURE);
}
/* NOTE: register values are not initialized */
}
unsigned short outshiftFeedbackRead(const unsigned short outputRegister)
{
assert(pOutshiftFeedbackOutput);
assert(outshiftFeedbackRegisterLen < outputRegister);
return ( * (pOutshiftFeedbackOutput + outputRegister));
}
void outshiftFeedbackDestroy(void)
{
free(pOutshiftFeedbackOutput);
free(pOutshiftFeedbackRegisters);
outshiftFeedbackRegisterLen = 0;
}
unsigned short outshiftGetRegLen(void)
{
return m_outshiftRegLen;
}
/**
* function to get the handle of an output register
* @param word word address
* @param bit bit
* @return handle
* @exception assert if the word or bit are not valid
*/
unsigned short outshiftGetHandle(const unsigned short word, const unsigned short bit)
{
assert(outshiftGetRegLen() > word);
assert(16 > bit);
return(0x10 * word + bit);
}