-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #92 from nasa-jpl/feat-el1008-driver
Feat el1008 driver
- Loading branch information
Showing
10 changed files
with
285 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
#include "jsd/jsd_el1008.h" | ||
|
||
#include <assert.h> | ||
#include <string.h> | ||
|
||
#include "jsd/jsd_sdo.h" | ||
|
||
/**************************************************** | ||
* Public functions | ||
****************************************************/ | ||
|
||
const jsd_el1008_state_t* jsd_el1008_get_state(jsd_t* self, uint16_t slave_id) { | ||
assert(self); | ||
assert(self->ecx_context.slavelist[slave_id].eep_id == | ||
JSD_EL1008_PRODUCT_CODE); | ||
|
||
jsd_el1008_state_t* state = &self->slave_states[slave_id].el1008; | ||
return state; | ||
} | ||
|
||
void jsd_el1008_read(jsd_t* self, uint16_t slave_id) { | ||
assert(self); | ||
assert(self->ecx_context.slavelist[slave_id].eep_id == | ||
JSD_EL1008_PRODUCT_CODE); | ||
|
||
jsd_el1008_state_t* state = &self->slave_states[slave_id].el1008; | ||
|
||
const jsd_el1008_txpdo_t* txpdo = | ||
(jsd_el1008_txpdo_t*)self->ecx_context.slavelist[slave_id].inputs; | ||
|
||
for (int ch = 0; ch < JSD_EL1008_NUM_CHANNELS; ++ch) { | ||
state->values[ch] = (1 << ch) & txpdo->channels; // Bit shift the channel to get value | ||
} | ||
} | ||
|
||
/**************************************************** | ||
* Private functions | ||
****************************************************/ | ||
|
||
bool jsd_el1008_init(jsd_t* self, uint16_t slave_id) { | ||
assert(self); | ||
assert(self->ecx_context.slavelist[slave_id].eep_id == | ||
JSD_EL1008_PRODUCT_CODE); | ||
assert(self->ecx_context.slavelist[slave_id].eep_man == | ||
JSD_BECKHOFF_VENDOR_ID); | ||
|
||
ec_slavet* slaves = self->ecx_context.slavelist; | ||
ec_slavet* slave = &slaves[slave_id]; | ||
|
||
slave->PO2SOconfigx = jsd_el1008_PO2SO_config; | ||
|
||
return true; | ||
} | ||
|
||
int jsd_el1008_PO2SO_config(ecx_contextt* ecx_context, uint16_t slave_id) { | ||
assert(ecx_context); | ||
assert(ecx_context->slavelist[slave_id].eep_id == JSD_EL1008_PRODUCT_CODE); | ||
|
||
// Since this function prototype is forced by SOEM, we have embedded a | ||
// reference to jsd.slave_configs within the ecx_context and extract it here. | ||
jsd_slave_config_t* slave_configs = | ||
(jsd_slave_config_t*)ecx_context->userdata; | ||
|
||
jsd_slave_config_t* config = &slave_configs[slave_id]; | ||
|
||
MSG("Configuring slave no: %u, SII inferred name: %s", slave_id, | ||
ecx_context->slavelist[slave_id].name); | ||
MSG("\t Configured name: %s", config->name); | ||
|
||
config->PO2SO_success = true; | ||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#ifndef JSD_EL1008_H | ||
#define JSD_EL1008_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#include "jsd/jsd.h" | ||
|
||
/** | ||
* @brief TxPDO struct used to read device data in SOEM IOmap | ||
* | ||
* Note: Struct order matters and must be packed. | ||
*/ | ||
typedef struct __attribute__((__packed__)) { | ||
uint8_t channels; // Each bit corresponds to a channel. | ||
} jsd_el1008_txpdo_t; | ||
|
||
/** @brief Initializes el1008 and registers the PO2SO function | ||
* | ||
* @param self pointer JSD context | ||
* @param slave_id index of device on EtherCAT bus | ||
* @return true on success, false on failure | ||
*/ | ||
bool jsd_el1008_init(jsd_t* self, uint16_t slave_id); | ||
|
||
/** | ||
* @brief Configuration function called by SOEM upon a PreOp to SafeOp state | ||
* transition that (re)configures EL1008 device settings | ||
* | ||
* @param ecx_context SOEM context pointer | ||
* @param slave_id index of device on EtherCAT bus | ||
* @return 1 on success, 0 on failure | ||
*/ | ||
int jsd_el1008_PO2SO_config(ecx_contextt* ecx_context, uint16_t slave_id); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#ifndef JSD_EL1008_PUB_H | ||
#define JSD_EL1008_PUB_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#include "jsd/jsd_pub.h" | ||
|
||
/** | ||
* @brief Read the EL1008 device state | ||
* | ||
* @param self Pointer to JSD context | ||
* @param slave_id Slave ID of EL1008 device | ||
* @return Pointer to EL1008 device state | ||
*/ | ||
const jsd_el1008_state_t* jsd_el1008_get_state(jsd_t* self, uint16_t slave_id); | ||
|
||
/** | ||
* @brief Converts raw PDO data to state data | ||
* | ||
* @param self pointer to JSD context | ||
* @param slave_id ID of EL1008 device | ||
*/ | ||
void jsd_el1008_read(jsd_t* self, uint16_t slave_id); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#ifndef JSD_EL1008_TYPES_H | ||
#define JSD_EL1008_TYPES_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#include "jsd/jsd_common_device_types.h" | ||
|
||
#define JSD_EL1008_PRODUCT_CODE (uint32_t)0x03f03052 | ||
#define JSD_EL1008_NUM_CHANNELS 8 // Each of the 8 values is 1 bit long. | ||
|
||
/** | ||
* @brief configuration struct for EL1008 device initialization | ||
*/ | ||
typedef struct { | ||
} jsd_el1008_config_t; | ||
|
||
/** | ||
* @brief Read struct for el1008 module | ||
*/ | ||
typedef struct { | ||
uint8_t values[JSD_EL1008_NUM_CHANNELS]; | ||
} jsd_el1008_state_t; | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#include <assert.h> | ||
#include <string.h> | ||
|
||
#include "jsd/jsd_el1008_pub.h" | ||
#include "jsd/jsd_el1008_types.h" | ||
#include "jsd_test_utils.h" | ||
|
||
extern bool quit; | ||
extern FILE* file; | ||
uint8_t slave_id; | ||
|
||
void telemetry_header() { | ||
if (!file) { | ||
return; | ||
} | ||
for (int i = 0; i < JSD_EL1008_NUM_CHANNELS; ++i) { | ||
fprintf(file, "EL1008_ch%d_level, ", i); | ||
} | ||
fprintf(file, "\n"); | ||
} | ||
|
||
void telemetry_data(void* self) { | ||
assert(self); | ||
|
||
if (!file) { | ||
return; | ||
} | ||
|
||
single_device_server_t* sds = (single_device_server_t*)self; | ||
const jsd_el1008_state_t* state = jsd_el1008_get_state(sds->jsd, slave_id); | ||
|
||
for (int i = 0; i < JSD_EL1008_NUM_CHANNELS; ++i) { | ||
fprintf(file, "%d,", state->values[i]); | ||
} | ||
fprintf(file, "\n"); | ||
fflush(file); | ||
} | ||
|
||
void print_info(void* self) { | ||
assert(self); | ||
|
||
single_device_server_t* sds = (single_device_server_t*)self; | ||
const jsd_el1008_state_t* state = jsd_el1008_get_state(sds->jsd, slave_id); | ||
MSG("Ch0: %d, Ch1: %d, Ch2: %d, Ch3: %d, Ch4: %d, Ch5: %d, Ch6: %d, Ch7: %d, ", | ||
state->values[0], state->values[1], state->values[2], state->values[3], | ||
state->values[4], state->values[5], state->values[6], state->values[7]); | ||
} | ||
|
||
void extract_data(void* self) { | ||
assert(self); | ||
|
||
single_device_server_t* sds = (single_device_server_t*)self; | ||
jsd_el1008_read(sds->jsd, slave_id); | ||
} | ||
|
||
void command(void* self) { (void)self; }; | ||
|
||
int main(int argc, char* argv[]) { | ||
if (argc != 4) { | ||
ERROR("Expecting exactly 3 arguments"); | ||
MSG("Usage: jsd_el1008_test <ifname> <el1008_slave_index> <loop_freq_hz>"); | ||
MSG("Example: $ jsd_el1008_test eth0 2 1000"); | ||
return 0; | ||
} | ||
|
||
char* ifname = strdup(argv[1]); | ||
slave_id = atoi(argv[2]); | ||
uint32_t loop_freq_hz = atoi(argv[3]); | ||
MSG("Configuring device %s, using slave %d", ifname, slave_id); | ||
MSG("Using frequency of %i hz", loop_freq_hz); | ||
|
||
single_device_server_t sds; | ||
|
||
sds_set_telemetry_header_callback(&sds, telemetry_header); | ||
sds_set_telemetry_data_callback(&sds, telemetry_data); | ||
sds_set_print_info_callback(&sds, print_info); | ||
sds_set_extract_data_callback(&sds, extract_data); | ||
sds_set_command_callback(&sds, command); | ||
|
||
sds_setup(&sds, loop_freq_hz); | ||
|
||
// Set device configuration here. | ||
jsd_slave_config_t my_config = {0}; | ||
|
||
snprintf(my_config.name, JSD_NAME_LEN, "unicorn"); | ||
my_config.configuration_active = true; | ||
my_config.product_code = JSD_EL1008_PRODUCT_CODE; | ||
|
||
jsd_set_slave_config(sds.jsd, slave_id, my_config); | ||
|
||
sds_run(&sds, ifname, "/tmp/jsd_el1008.csv"); | ||
|
||
free(ifname); | ||
|
||
return 0; | ||
} |