Skip to content

Commit 47ec301

Browse files
committed
device: device api extension proposal
A draft showing how to handle external API with devices. Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
1 parent 4f16268 commit 47ec301

File tree

3 files changed

+138
-1
lines changed

3 files changed

+138
-1
lines changed

include/device.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ extern "C" {
2929

3030
#define Z_DEVICE_MAX_NAME_LEN 48
3131

32+
/**@defgroup DEVICE_EXT_API_FLAGS Flags identifying extension APIs.
33+
* @{
34+
*/
35+
36+
/** @brief onoff service supported by the device. */
37+
#define DEVICE_EXT_API_ONOFF BIT(0)
38+
39+
/** @brief foo API supported by the device. */
40+
#define DEVICE_EXT_API_FOO BIT(1)
41+
42+
/**@} */
43+
3244
/**
3345
* @def DEVICE_INIT
3446
*
@@ -264,6 +276,18 @@ struct device_config {
264276
const void *config_info;
265277
};
266278

279+
/** @brief Extension API's structure/
280+
*
281+
* @param capabilities Mask of supported APIs, see DEVICE_EXT_API_FLAGS.
282+
* @param data If driver has only one capability then it is a pointer
283+
* to data associated with API. Otherwise it is an array
284+
* of pointer.
285+
*/
286+
struct device_ext_api {
287+
u32_t capabilities;
288+
void *data;
289+
}
290+
267291
/**
268292
* @brief Runtime device structure (In memory) Per driver instance
269293
* @param device_config Build time config information
@@ -275,6 +299,7 @@ struct device {
275299
const struct device_config *config;
276300
const void *driver_api;
277301
void *driver_data;
302+
struct device_ext_api *ext_api;
278303
};
279304

280305
void z_sys_device_do_config_level(s32_t level);
@@ -293,6 +318,51 @@ void z_sys_device_do_config_level(s32_t level);
293318
*/
294319
__syscall struct device *device_get_binding(const char *name);
295320

321+
/** @brief Check if given extension is supported.
322+
*
323+
* @param dev Device.
324+
* @param api_mask Bit mask identifiing an extension.
325+
*
326+
* @return True if supported, false otherwise.
327+
*/
328+
static inline bool z_device_ext_api_supported(struct device *dev, u32_t api_mask)
329+
{
330+
if (dev->ext_api == NULL) {
331+
return false;
332+
}
333+
334+
return dev->ext_api->capabilities & api_mask ? true : false;
335+
}
336+
337+
/** @brief Get extension specific data.
338+
*
339+
* If device supports multiple extensions then assosiated data is stored in
340+
* array. Data is ordered starting from LSB extension bit. If only one extension
341+
* is supported then pointer to associated data instead of array of pointers is
342+
* used.
343+
*
344+
* @param dev Device.
345+
* @param api_mask Bit mask identifiing an extension.
346+
*
347+
* @return Extension data
348+
*/
349+
static inline void *z_device_ext_api_get_data(struct device *dev,
350+
u32_t api_mask)
351+
{
352+
u32_t mask;
353+
u32_t idx;
354+
355+
if (!(dev->ext_api->capabilities & (dev->ext_api->capabilities - 1))) {
356+
return dev->ext_api->data;
357+
}
358+
359+
/* clean all higher bits to get numer of bits set up to current bit. */
360+
mask = (api_mask - 1) & dev->ext_api->capabilities;
361+
idx = __builtin_popcount(mask);
362+
363+
return dev->ext_api->data[idx];
364+
}
365+
296366
/**
297367
* @}
298368
*/

include/sys/onoff.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,52 @@ static inline void onoff_client_init_callback(struct onoff_client *cli,
423423
};
424424
}
425425

426+
/** @brief Get onoff service from the device.
427+
*
428+
* @param dev Device.
429+
* @param srv Location where service handler is stored.
430+
*
431+
* @retval 0 on success.
432+
* @retval -ENOTSUP is API is not supported by the device.
433+
*/
434+
static inline int device_get_onoff_service(struct device *dev,
435+
struct onoff_service **srv)
436+
{
437+
if (!z_device_ext_api_supported(dev, DEVICE_EXT_API_ONOFF)) {
438+
return -ENOTSUP;
439+
}
440+
441+
*srv = (struct ononff_service *) z_device_ext_api_get_data(dev,
442+
DEVICE_EXT_API_ONOFF);
443+
return 0;
444+
}
445+
446+
/** @brief Get onoff service from the device subsystem.
447+
*
448+
* Used when device has more than one onoff service.
449+
*
450+
* @param dev Device.
451+
* @param subsys Subsys id.
452+
* @param srv Location where service handler is stored.
453+
*
454+
* @retval 0 on success.
455+
* @retval -ENOTSUP is API is not supported by the device.
456+
*/
457+
static inline int device_subsys_get_onoff_service(struct device *dev,
458+
u32_t subsys,
459+
struct onoff_service **srv)
460+
{
461+
void **data;
462+
if (!z_device_ext_api_supported(dev, DEVICE_EXT_API_ONOFF)) {
463+
return -ENOTSUP;
464+
}
465+
466+
data = (void **)z_device_ext_api_get_data(dev, DEVICE_EXT_API_ONOFF);
467+
*srv = (struct ononff_service *)data[subsys];
468+
469+
return 0;
470+
}
471+
426472
/**
427473
* @brief Request a reservation to use an on-off service.
428474
*

samples/hello_world/src/main.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,29 @@
66

77
#include <zephyr.h>
88
#include <sys/printk.h>
9+
#include <device.h>
10+
#include <sys/off.h>
911

1012
void main(void)
1113
{
12-
printk("Hello World! %s\n", CONFIG_BOARD);
14+
struct device *clock = device_get_binding("CLOCK");
15+
struct device *spi = device_get_binding("SPI");
16+
struct onoff_client client;
17+
struct onoff_service *srv;
18+
int err;
19+
20+
err = device_subsys_get_onoff_service(clock, subsys, &srv);
21+
if (err < 0) {
22+
LOG_ERR("Failed to get device onoff service (err: %d)", err);
23+
}
24+
25+
err = onoff_request(srv, &client);
26+
27+
/* hypothetical another api supported by the device */
28+
err = device_get_op_mngr(spi, &op_mngr);
29+
if (err < 0) {
30+
31+
}
32+
33+
err = op_mngr_schedule(op_mngr, transaction);
1334
}

0 commit comments

Comments
 (0)