Statistics
| Branch: | Tag: | Revision:

amiro-os / unittests / periphery-lld / src / ut_alld_vcnl4020.c @ 3940ba8a

History | View | Annotate | Download (12.3 KB)

1
/*
2
AMiRo-OS is an operating system designed for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2019  Thomas Schöpping et al.
4

5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9

10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14

15
You should have received a copy of the GNU General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18

    
19
#include <ut_alld_vcnl4020.h>
20

    
21
#if ((AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020)) || defined(__DOXYGEN__)
22

    
23
/******************************************************************************/
24
/* LOCAL DEFINITIONS                                                          */
25
/******************************************************************************/
26

    
27
#define INTERRUPT_EVENT_ID            1
28

    
29
#define INTERRUPT_THRESHOLD           0x2000
30

    
31
/******************************************************************************/
32
/* EXPORTED VARIABLES                                                         */
33
/******************************************************************************/
34

    
35
/******************************************************************************/
36
/* LOCAL TYPES                                                                */
37
/******************************************************************************/
38

    
39
/******************************************************************************/
40
/* LOCAL VARIABLES                                                            */
41
/******************************************************************************/
42

    
43
/******************************************************************************/
44
/* LOCAL FUNCTIONS                                                            */
45
/******************************************************************************/
46

    
47
/******************************************************************************/
48
/* EXPORTED FUNCTIONS                                                         */
49
/******************************************************************************/
50

    
51
aos_utresult_t utAlldVcnl4020Func(BaseSequentialStream* stream, aos_unittest_t* ut)
52
{
53
  aosDbgCheck((ut->data != NULL) &&
54
              (((ut_vcnl4020data_t*)(ut->data))->vcnld != NULL) &&
55
              (((ut_vcnl4020data_t*)(ut->data))->evtsource != NULL));
56

    
57
  // local variables
58
  aos_utresult_t result = {0, 0};
59
  uint32_t status;
60
  uint8_t reg_buf[4];
61
  uint8_t* reg_8 = (uint8_t*)(reg_buf);
62
  uint16_t* reg_16 = (uint16_t*)(reg_buf);
63
  event_listener_t event_listener;
64
  aos_timestamp_t tcurrent, tend;
65

    
66
  chprintf(stream, "reading register...\n");
67
  status = vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_IDREV, &reg_8[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
68
  if ((status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) && reg_8[0] == 0x21u) {
69
    aosUtPassed(stream, &result);
70
  } else {
71
    aosUtFailedMsg(stream, &result, "0x%08X; 0x%08X\n", status, reg_8[0]);
72
  }
73

    
74
  chprintf(stream, "writing register...\n");
75
  status = vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_PROXRATE, VCNL4020_LLD_PROXRATEREG_250_HZ, ((ut_vcnl4020data_t*)(ut->data))->timeout);
76
  status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_PROXRATE, &reg_8[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
77
  status |= (reg_8[0] == VCNL4020_LLD_PROXRATEREG_250_HZ) ? 0x0000 : 0x0100;
78
  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_CMD, (VCNL4020_LLD_CMDREG_ALSEN | VCNL4020_LLD_CMDREG_PROXEN | VCNL4020_LLD_CMDREG_SELFTIMED), ((ut_vcnl4020data_t*)(ut->data))->timeout);
79
  status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_CMD, &reg_8[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
80
  status |= (reg_8[0] & (VCNL4020_LLD_CMDREG_ALSEN | VCNL4020_LLD_CMDREG_PROXEN | VCNL4020_LLD_CMDREG_SELFTIMED)) ? 0x0000 : 0x0200;
81

    
82
  if (status == APAL_STATUS_OK || status == APAL_STATUS_WARNING) {
83
    aosUtPassed(stream, &result);
84
  } else {
85
    aosUtFailedMsg(stream, &result, "0x%08X, 0x%02X\n", status, reg_8[0]);
86
  }
87

    
88
  chprintf(stream, "reading ambient light for ten seconds...\n");
89
  status = APAL_STATUS_OK;
90
  for (uint8_t i = 0; i < 10; ++i) {
91
    aosThdSSleep(1);
92
    status |= vcnl4020_lld_readals(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
93
    chprintf(stream, "\t\tambient light: 0x%04X\n", reg_16[0]);
94
  }
95
  status |= (reg_16[0] == 0x0000) ? 0x10 : 0x00;
96
  if (status == APAL_STATUS_OK) {
97
    aosUtPassed(stream, &result);
98
  } else {
99
    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
100
  }
101

    
102
  chprintf(stream, "reading proximity for ten seconds...\n");
103
  status = APAL_STATUS_OK;
104
  for (uint8_t i = 0; i < 10; ++i) {
105
    aosThdSSleep(1);
106
    status |= vcnl4020_lld_readprox(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
107
    chprintf(stream, "\t\tproximity: 0x%04X\n", reg_16[1]);
108
  }
109
  status |= (reg_16[1] == 0x0000) ? 0x10 : 0x00;
110
  if (status == APAL_STATUS_OK) {
111
    aosUtPassed(stream, &result);
112
  } else {
113
    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
114
  }
115

    
116
  chprintf(stream, "reading ambient light and proximity for ten seconds...\n");
117
  status = APAL_STATUS_OK;
118
  for (uint8_t i = 0; i < 10; ++i) {
119
    aosThdSSleep(1);
120
    status |= vcnl4020_lld_readalsandprox(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
121
    chprintf(stream, "\t\tambient light: 0x%04X\tproximity: 0x%04X\n", reg_16[0], reg_16[1]);
122
  }
123
  status |= (reg_16[0] == 0x0000 || reg_16[1] == 0x0000) ? 0x10 : 0x00;
124
  if (status == APAL_STATUS_OK) {
125
    aosUtPassed(stream, &result);
126
  } else {
127
    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
128
  }
129

    
130
  chprintf(stream, "reading low threshold register...\n");
131
  status = vcnl4020_lld_readlth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
132
  if (status == APAL_STATUS_OK) {
133
    aosUtPassed(stream, &result);
134
  } else {
135
    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
136
  }
137

    
138
  chprintf(stream, "reading high threshold register...\n");
139
  status = vcnl4020_lld_readhth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
140
  if (status == APAL_STATUS_OK) {
141
    aosUtPassedMsg(stream, &result, "0x%04X\n", reg_16[1]);
142
  } else {
143
    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
144
  }
145

    
146
  chprintf(stream, "reading both threshold registers...\n");
147
  status = vcnl4020_lld_readth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
148
  if (status == APAL_STATUS_OK) {
149
    aosUtPassedMsg(stream, &result, "low: 0x%04X; high: 0x%04X\n", reg_16[0], reg_16[1]);
150
  } else {
151
    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
152
  }
153

    
154
  chprintf(stream, "writing low threshold register...\n");
155
  status = vcnl4020_lld_writelth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0xFFFFu, ((ut_vcnl4020data_t*)(ut->data))->timeout);
156
  status |= vcnl4020_lld_readlth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
157
  if (status == APAL_STATUS_OK && reg_16[0] == 0xFFFFu) {
158
    aosUtPassed(stream, &result);
159
  } else {
160
    aosUtFailedMsg(stream, &result, "0x%08X, 0x%04X\n", status, reg_16[0]);
161
  }
162

    
163
  chprintf(stream, "writing high threshold register...\n");
164
  status = vcnl4020_lld_writehth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0xFFFFu, ((ut_vcnl4020data_t*)(ut->data))->timeout);
165
  status |= vcnl4020_lld_readhth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
166
  if (status == APAL_STATUS_OK && reg_16[1] == 0xFFFFu) {
167
    aosUtPassed(stream, &result);
168
  } else {
169
    aosUtFailedMsg(stream, &result, "0x%08X, 0x%04X\n", status, reg_16[1]);
170
  }
171

    
172
  chprintf(stream, "writing both threshold registers...\n");
173
  status = vcnl4020_lld_writeth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0x5555u, 0xAAAAu, ((ut_vcnl4020data_t*)(ut->data))->timeout);
174
  status |= vcnl4020_lld_readth(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], &reg_16[1], ((ut_vcnl4020data_t*)(ut->data))->timeout);
175
  if (status == APAL_STATUS_OK && reg_16[0] == 0x5555u && reg_16[1] == 0xAAAAu) {
176
    aosUtPassed(stream, &result);
177
  } else {
178
    aosUtFailedMsg(stream, &result, "0x%08X, 0x%04X, 0x%04X\n", status, reg_16[0], reg_16[1]);
179
  }
180

    
181
  chprintf(stream, "test interrupts...\n");
182
  chprintf(stream, "(thresholds are 0x%04X and 0x%04X)\n", 0, INTERRUPT_THRESHOLD);
183
  chEvtRegister(((ut_vcnl4020data_t*)(ut->data))->evtsource, &event_listener, INTERRUPT_EVENT_ID);
184
  aosSysGetUptime(&tend);
185
  tend += 30 * MICROSECONDS_PER_SECOND;
186
  status = vcnl4020_lld_writeth(((ut_vcnl4020data_t*)(ut->data))->vcnld, 0x0000, INTERRUPT_THRESHOLD, ((ut_vcnl4020data_t*)(ut->data))->timeout);
187
  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTCTRL, VCNL4020_LLD_INTCTRLREG_THRES_EN, ((ut_vcnl4020data_t*)(ut->data))->timeout);
188
  do {
189
    // read proximity data, interrupt event information and interrupt status
190
    const eventmask_t emask = chEvtWaitOneTimeout(EVENT_MASK(INTERRUPT_EVENT_ID), chTimeUS2I(10*MICROSECONDS_PER_MILLISECOND));
191
    const eventflags_t eflags = chEvtGetAndClearFlags(&event_listener);
192
    status |= vcnl4020_lld_readprox(((ut_vcnl4020data_t*)(ut->data))->vcnld, &reg_16[0], ((ut_vcnl4020data_t*)(ut->data))->timeout);
193
    status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, &reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
194
    if (emask == EVENT_MASK(INTERRUPT_EVENT_ID) &&
195
        eflags == ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
196
        reg_8[2] == VCNL4020_LLD_INTSTATUSREG_THHIGH) {
197
      // true positive (correct case)
198
      chprintf(stream, "\t\tinterrupt detected: prox = 0x%04X\n", reg_16[0]);
199
      aosThdMSleep(100);
200
    }
201
    else if (emask != EVENT_MASK(INTERRUPT_EVENT_ID) &&
202
             eflags != ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
203
             reg_8[2] != VCNL4020_LLD_INTSTATUSREG_THHIGH) {
204
      // true negative (correct case)
205
      // do nothing, just keep on looping
206
    }
207
    else if (emask == EVENT_MASK(INTERRUPT_EVENT_ID) &&
208
             eflags == ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
209
             reg_8[2] != 0 ) {
210
      // false positive
211
      status |= 0x1000;
212
      chprintf(stream, "\t\tfalse positive: intstatus = 0x%02X; prox = 0x%04X\n", reg_8[2], reg_16[0]);
213
    }
214
    else if (emask != EVENT_MASK(INTERRUPT_EVENT_ID) &&
215
             eflags != ((ut_vcnl4020data_t*)(ut->data))->evtflags &&
216
             reg_8[2] == 0) {
217
      // false negative
218
      status |= 0x2000;
219
      chprintf(stream, "\t\tfalse negative: intstatus = 0x%02X; prox = 0x%04X\n", reg_8[2], reg_16[0]);
220
    } // any other events are just ignored
221
    // reset interrupt status
222
    if (reg_8[2] != 0) {
223
      status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
224
    }
225
    aosSysGetUptime(&tcurrent);
226
  } while (tcurrent < tend);
227
  chEvtUnregister(((ut_vcnl4020data_t*)(ut->data))->evtsource, &event_listener);
228
  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTCTRL, 0, ((ut_vcnl4020data_t*)(ut->data))->timeout);
229
  status |= vcnl4020_lld_readreg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, &reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
230
  status |= vcnl4020_lld_writereg(((ut_vcnl4020data_t*)(ut->data))->vcnld, VCNL4020_LLD_REGADDR_INTSTATUS, reg_8[2], ((ut_vcnl4020data_t*)(ut->data))->timeout);
231
  if (status == APAL_STATUS_SUCCESS || status == APAL_STATUS_WARNING) {
232
    aosUtPassed(stream, &result);
233
  } else {
234
    aosUtFailedMsg(stream, &result, "0x%08X\n", status);
235
  }
236

    
237
  aosUtInfoMsg(stream, "driver object memory footprint: %u bytes\n", sizeof(VCNL4020Driver));
238

    
239
  return result;
240
}
241

    
242
#endif /* (AMIROOS_CFG_TESTS_ENABLE == true) && defined(AMIROLLD_CFG_USE_VCNL4020) */