📄 xbee_gpio_client.c
字号:
} gpio_signal[GPIO_MAX_SIGNALS];
enum { // GPIO states
CLIENT_STATE_IDLE = 0, // Client state idle must be zero
CLIENT_STATE_REQ_INFO,
CLIENT_STATE_PARSE_INFO,
CLIENT_STATE_NEW_NAME,
CLIENT_STATE_REQ_NAME,
CLIENT_STATE_PARSE_NAME,
CLIENT_STATE_REQ_ANARANGE,
CLIENT_STATE_PARSE_ANARANGE,
CLIENT_STATE_REQ_READ,
CLIENT_STATE_PARSE_READ,
CLIENT_STATE_PARSE_WRITE
};
enum { // Main function states
ZB_IDLE,
ZB_NODE_OPEN,
ZB_EXIT
};
enum { // Command parsing states
PARSE_CMD, // Parse command component
PARSE_SIGNAL, // Parse signal ID component
PARSE_VALUE, // Parse value component
PARSE_DONE, // Parse complete, execute command and exit
PARSE_ERROR, // Error, print message and exit (keep below PARSE_DONE)
PARSE_EXIT // Exit parsing function (keep below PARSE_DONE)
};
enum { // Signal commands
SIGNAL_GET, // Get value(s) from one or all signal sources
SIGNAL_SET // Set value to output signal
};
#define SHOW_NET_HELP 1
#define SHOW_GPIO_HELP 2
#define SHOW_SIGNALS 4
// function prototypes for sending packet requests to a gpio node
void find_gpio_servers(void);
int query_gpio_node(void);
int request_gpio_info(int node_index);
int request_gpio_names(int node_index, int io_start, int io_end);
int request_gpio_ana_range(int node_index, int io_start, int io_end);
int request_gpio_read(int node_index, int io_start, int io_end);
void gpio_help(int flags);
int request_gpio(int node_index, int cluster, char *data, int len)
{
int err;
_zb_NodeData_t *nodeData;
zb_sendAddress_t sendAddr;
nodeData = GET_NODE_DATA(node_index);
if (nodeData == NULL) {
#ifdef GPIO_VERBOSE
printf("request_gpio: invalid node_index (%d)\n", node_index);
#endif
return -1;
}
zb_MakeEndpointClusterAddr(node_index, XBEE_ENDPOINT_RESPONSE,
XBEE_ENDPOINT_GPIO, cluster, &sendAddr);
sendAddr.msg = data;
sendAddr.msglen = len;
#ifdef GPIO_VERBOSE
printf("sending cluster 0x%02x to node %d:\n", cluster, node_index);
xb_hexdump(data, len);
#endif
err = zb_send(&sendAddr);
if (err) {
#ifdef GPIO_VERBOSE
printf("request_gpio: error %d sending\n", err);
#endif
return err;
}
#ifdef GPIO_VERBOSE
printf("request_gpio: sent 0x%02x request\n", cluster);
#endif
gpio_device[gpio_index].last_request = (byte) cluster;
gpio_device[gpio_index].request_sent = MS_TIMER;
return 0;
}
void find_gpio_servers(void)
{
int node_index, i;
_zb_NodeData_t *nodeData;
int err;
printf("\nScanning network nodes for GPIO servers.\n\n");
memset(&gpio_device, 0, sizeof(gpio_device));
for (i = 0; i < GPIO_MAX_SERVERS; gpio_device[i++].node_index = -1);
node_index = gpio_index = 0;
while( nodeData=GET_NODE_DATA(node_index) )
{
#ifdef GPIO_VERBOSE
printf("%d A:%04X P:%04X %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
node_index, ntohs(nodeData->nwk_addr), ntohs(nodeData->parent_NetAddr),
nodeData->who[0],nodeData->who[1],
nodeData->who[2],nodeData->who[3],nodeData->who[4],
nodeData->who[5],nodeData->who[6],nodeData->who[7]);
printf(" %s [%s]\n", (nodeData->active) ? " Active" : "Inactive",
nodeData->remoteID);
#endif
// Query possible gpio device
gpio_device[gpio_index].state = CLIENT_STATE_REQ_INFO;
gpio_device[gpio_index].node_index = node_index;
while (!query_gpio_node()) {
zb_tick();
}
// See if response was received from gpio info request
if (gpio_device[gpio_index].io_count) {
printf(" %d: Type = %04x, I/O Count = %d\n", gpio_index,
gpio_device[gpio_index].device_type,
gpio_device[gpio_index].io_count);
// Increase the server count
gpio_index++;
if (gpio_index >= GPIO_MAX_SERVERS) {
// If maximum reached, stop scanning
return;
}
}
// Move to next node on network
++node_index;
}
}
int query_gpio_node(void)
{
int i, end, min, max;
gpio_device_t *gpio;
unsigned long check;
gpio = &gpio_device[gpio_index];
switch (gpio->state) {
case CLIENT_STATE_IDLE:
gpio->ep_count = 0;
break; // When idle, node discovery complete
case CLIENT_STATE_REQ_INFO:
// Send GPIO info request to see if node is a GPIO server
// If error received, set state to idle to move on
gpio->state = (request_gpio_info(gpio->node_index) ?
CLIENT_STATE_IDLE : CLIENT_STATE_PARSE_INFO);
break;
case CLIENT_STATE_PARSE_INFO:
// Wait for I/O count from server
if (gpio->io_count) {
gpio->state = CLIENT_STATE_IDLE;
}
break;
case CLIENT_STATE_NEW_NAME:
// Clear any existing signal information and drop into request
memset(&gpio_signal, 0, sizeof(gpio_signal));
case CLIENT_STATE_REQ_NAME:
// Query server for names and info for all available signals
min = (gpio->ep_count ? gpio->io_count - gpio->ep_count : 0);
if (!request_gpio_names(gpio->node_index, min, gpio->io_count - 1))
{
gpio->state = CLIENT_STATE_PARSE_NAME;
gpio->ep_count = gpio->io_count - min;
}
break;
case CLIENT_STATE_REQ_ANARANGE:
// Find group of analog signal inputs
if (gpio->ep_count) {
min = gpio->last_ep - gpio->ep_count + 1;
}
else {
for (i = max = 0, min = -1, end = gpio->io_count;
i < end; i++)
{
if (gpio_signal[i].type == XBEE_GPIO_TYPE_ANALOG_IN) {
if (min < 0) min = i;
max = i;
}
}
}
// If analog inputs exist, query for range settings
if (min >= 0 && !request_gpio_ana_range(gpio->node_index, min, max)) {
gpio->state = CLIENT_STATE_PARSE_ANARANGE;
gpio->ep_count = max - min + 1;
}
else {
gpio->state = CLIENT_STATE_IDLE;
gpio_help(SHOW_GPIO_HELP);
}
break;
case CLIENT_STATE_REQ_READ:
request_gpio_read(gpio->node_index, gpio->last_ep - gpio->ep_count + 1,
gpio->last_ep);
break;
case CLIENT_STATE_PARSE_NAME:
case CLIENT_STATE_PARSE_ANARANGE:
case CLIENT_STATE_PARSE_READ:
case CLIENT_STATE_PARSE_WRITE:
// Wait for end point count to drop to zero, then node is back to idle
if (gpio->ep_count == 0) {
if (gpio->state == CLIENT_STATE_PARSE_ANARANGE) {
gpio_help(SHOW_GPIO_HELP);
gpio->state = CLIENT_STATE_IDLE;
}
else {
if (gpio->state == CLIENT_STATE_PARSE_NAME) {
gpio->state = CLIENT_STATE_IDLE;
gpio_help(SHOW_SIGNALS | SHOW_GPIO_HELP);
return 1; // Printing help may cause timeout so return here
}
else {
printf("\nG> ");
gpio->state = CLIENT_STATE_IDLE;
}
}
}
break;
default:
gpio->state = CLIENT_STATE_IDLE;
break;
}
if (gpio->state != CLIENT_STATE_IDLE) {
// Check for timeout of response/operation
check = MS_TIMER;
if (check - gpio->request_sent > GPIO_TIMEOUT) {
#ifdef GPIO_VERBOSE
printf("\nResponse has timed out. (%d:%d:%d)\n\n", gpio_index,
gpio->node_index , gpio->state);
#endif
gpio->state = CLIENT_STATE_IDLE;
}
else {
return 0;
}
}
return 1;
}
int request_gpio_info(int node_index)
{
int err;
// send a single null byte, msg points to an empty string (null byte)
err = request_gpio(node_index, XBEE_GPIO_CLUST_INFO, "", 1);
if (! err) {
gpio_device[gpio_index].node_index = node_index;
gpio_device[gpio_index].io_count = 0;
}
return err;
}
void xbeeGpioDevInfoResp(char *frame, int framelen)
{
xbee_frame_gpio_info_t *gpio_info;
gpio_info = (xbee_frame_gpio_info_t *) frame;
if (framelen < sizeof(*gpio_info)) {
#ifdef GPIO_VERBOSE
printf("dev info response too short (%d bytes)\n", framelen);
#endif
return;
}
#ifdef GPIO_VERBOSE
printf("Received device info response:\n");
printf(" Cluster Ver: %d I/O Count: %u\n",
gpio_info->protocol_ver, gpio_info->io_count);
printf(" Manufacturer: 0x%04x Device: 0x%04x Firmware: %u.%02u\n",
gpio_info->manufacturer, gpio_info->device_type,
gpio_info->firmware_ver >> 8, gpio_info->firmware_ver & 0x00FF);
#endif
gpio_device[gpio_index].io_count = gpio_info->io_count;
gpio_device[gpio_index].device_type = gpio_info->device_type;
}
int request_gpio_iorange(int node_index, int cluster, int io_start, int io_end)
{
int i, req_count;
char request[XBEE_MAX_RFPAYLOAD];
req_count = 0;
for (i = io_start; (i <= io_end) && (req_count < XBEE_RFPAYLOAD_SIZE); i++) {
request[req_count++] = i;
}
return request_gpio(node_index, cluster, request, req_count);
}
int request_gpio_names(int node_index, int io_start, int io_end)
{
return request_gpio_iorange(node_index, XBEE_GPIO_CLUST_NAME, io_start,
io_end);
}
void xbeeGpioNameResp(char *data, int datalen)
{
int index;
xbee_gpio_rec_name_resp_t *resp;
#ifdef GPIO_VERBOSE
printf("parsing name response\n");
xb_hexdump(data, datalen);
#endif
while (datalen >= 2) {
resp = (xbee_gpio_rec_name_resp_t *) data;
if (resp->type == 0xFF) {
#ifdef GPIO_VERBOSE
printf(" io%3d: invalid\n");
#endif
datalen -= 2;
data += 2;
} else {
if (datalen < 3) {
#ifdef GPIO_VERBOSE
printf(" incomplete packet, %d extra byte(s) at end\n", datalen);
#endif
datalen = 0;
break;
}
if (resp->namelen + 3 > datalen) {
#ifdef GPIO_VERBOSE
printf(" io%3d: decode error, namelen (%d) too long for packet\n",
resp->signal, resp->namelen);
#endif
}
if (resp->namelen > 20) {
#ifdef GPIO_VERBOSE
printf(" io%3d: decode error, namelen (%d) invalid\n",
resp->signal, resp->namelen);
#endif
}
memcpy(gpio_signal[resp->signal].name, resp->name, resp->namelen);
gpio_signal[resp->signal].name[resp->namelen] = '\0';
gpio_signal[resp->signal].index = resp->signal;
gpio_signal[resp->signal].type = resp->type;
if (gpio_device[gpio_index].ep_count) {
gpio_device[gpio_index].ep_count--;
}
#ifdef GPIO_VERBOSE
printf(" io%3d: type 0x%02x, name=%s\n", resp->signal, resp->type,
gpio_signal[resp->signal].name);
#endif
datalen -= resp->namelen + 3;
data += resp->namelen + 3;
}
}
#ifdef GPIO_VERBOSE
if (datalen)
{
printf(" bad packet, 1 extra byte at end (0x%02x)\n", *data);
}
#endif
if (gpio_device[gpio_index].ep_count) {
gpio_device[gpio_index].state = CLIENT_STATE_REQ_NAME;
}
}
int request_gpio_ana_range(int node_index, int io_start, int io_end)
{
return request_gpio_iorange(node_index, XBEE_GPIO_CLUST_ANA_RANGE, io_start,
io_end);
}
void xbeeGpioAnaRangeResp(char *data, int datalen)
{
int units_len, record_len;
char units[16];
xbee_gpio_rec_ar_resp_units_t *resp;
xbee_gpio_rec_ar_resp_range_t *range;
#ifdef GPIO_VERBOSE
printf("parsing analog range response\n");
xb_hexdump(data, datalen);
#endif
while (datalen >= 2) {
resp = (xbee_gpio_rec_ar_resp_units_t *) data;
if (resp->length == 0xFF) {
#ifdef GPIO_VERBOSE
printf(" %s(%3d): invalid/not analog I/O\n",
gpio_signal[resp->signal].name, resp->signal);
#endif
datalen -= 2;
data += 2;
} else {
units_len = resp->length & 0x0F;
record_len = 2 + units_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -