tag_create_function find_tag_create_func(attr attributes) { int i = 0; const char *protocol = attr_get_str(attributes, "protocol", NULL); const char *make = attr_get_str(attributes, "make", attr_get_str(attributes, "manufacturer", NULL)); const char *family = attr_get_str(attributes, "family", NULL); const char *model = attr_get_str(attributes, "model", NULL); int num_entries = (sizeof(tag_type_map)/sizeof(tag_type_map[0])); /* if protocol is set, then use it to match. */ if(protocol && str_length(protocol) > 0) { for(i=0; i < num_entries; i++) { if(tag_type_map[i].protocol && str_cmp(tag_type_map[i].protocol, protocol) == 0) { pdebug(DEBUG_INFO,"Matched protocol=%s", protocol); return tag_type_map[i].tag_constructor; } } } else { /* match make/family/model */ for(i=0; i < num_entries; i++) { if(tag_type_map[i].make && make && str_cmp_i(tag_type_map[i].make, make) == 0) { pdebug(DEBUG_INFO,"Matched make=%s",make); if(tag_type_map[i].family) { if(family && str_cmp_i(tag_type_map[i].family, family) == 0) { pdebug(DEBUG_INFO, "Matched make=%s family=%s", make, family); if(tag_type_map[i].model) { if(model && str_cmp_i(tag_type_map[i].model, model) == 0) { pdebug(DEBUG_INFO, "Matched make=%s family=%s model=%s", make, family, model); return tag_type_map[i].tag_constructor; } } else { /* matches until a NULL */ pdebug(DEBUG_INFO, "Matched make=%s family=%s model=NULL", make, family); return tag_type_map[i].tag_constructor; } } } else { /* matched until a NULL, so we matched */ pdebug(DEBUG_INFO, "Matched make=%s family=NULL model=NULL", make); return tag_type_map[i].tag_constructor; } } } } /* no match */ return NULL; }
extern float attr_get_float(attr attrs, const char *name, float def) { float res; int rc; const char *str_val = attr_get_str(attrs,name, NULL); if(!str_val) { return def; } rc = str_to_float(str_val, &res); if(rc) { /* format error? */ return def; } else { return res; } }
plc_tag ab_tag_create(attr attribs) { ab_tag_p tag = AB_TAG_NULL; const char *path; int rc; int debug = attr_get_int(attribs,"debug",0); pdebug(debug,"Starting."); /* * allocate memory for the new tag. Do this first so that * we have a vehicle for returning status. */ tag = (ab_tag_p)mem_alloc(sizeof(struct ab_tag_t)); if(!tag) { pdebug(debug,"Unable to allocate memory for AB EIP tag!"); return PLC_TAG_NULL; } /* store the debug status */ tag->debug = debug; /* * check the CPU type. * * This determines the protocol type. */ if(check_cpu(tag, attribs) != PLCTAG_STATUS_OK) { tag->status = PLCTAG_ERR_BAD_DEVICE; return (plc_tag)tag; } /* AB PLCs are little endian. */ tag->endian = PLCTAG_DATA_LITTLE_ENDIAN; /* allocate memory for the data */ tag->elem_count = attr_get_int(attribs,"elem_count",1); tag->elem_size = attr_get_int(attribs,"elem_size",0); tag->size = (tag->elem_count) * (tag->elem_size); if(tag->size == 0) { /* failure! Need data_size! */ tag->status = PLCTAG_ERR_BAD_PARAM; return (plc_tag)tag; } tag->data = (uint8_t*)mem_alloc(tag->size); if(tag->data == NULL) { tag->status = PLCTAG_ERR_NO_MEM; return (plc_tag)tag; } /* get the connection path, punt if there is not one and we have a Logix-class PLC. */ path = attr_get_str(attribs,"path",NULL); if(path == NULL && tag->protocol_type == AB_PROTOCOL_LGX) { tag->status = PLCTAG_ERR_BAD_PARAM; return (plc_tag)tag; } /* make sure the global mutex is set up */ rc = check_mutex(tag->debug); if(rc != PLCTAG_STATUS_OK) { tag->status = rc; return (plc_tag)tag; } tag->first_read = 1; /* * now we start the part that might conflict with other threads. * * The rest of this is inside a locked block. */ pdebug(debug,"Locking mutex"); critical_block(io_thread_mutex) { /* * set up tag vtable. This is protocol specific */ tag->vtable = set_tag_vtable(tag); if(!tag->vtable) { pdebug(debug,"Unable to set tag vtable!"); tag->status = PLCTAG_ERR_BAD_PARAM; break; } /* * Check the request IO handler thread. */ if(!io_handler_thread) { rc = thread_create((thread_p*)&io_handler_thread,request_handler_func, 32*1024, NULL); if(rc != PLCTAG_STATUS_OK) { pdebug(debug,"Unable to create request handler thread!"); tag->status = rc; break; } } /* * Find or create a session. */ if(find_or_create_session(tag, attribs) != PLCTAG_STATUS_OK) { pdebug(debug,"Unable to create session!"); tag->status = PLCTAG_ERR_BAD_GATEWAY; break; } /* * parse the link path into the tag. Note that it must * pad the byte string to a multiple of 16-bit words. The function * also adds the protocol/PLC specific routing information to the * links specified. This fills in fields in the connection about * any DH+ special data. * * Skip this if we don't have a path. */ if(path && cip_encode_path(tag,path) != PLCTAG_STATUS_OK) { pdebug(debug,"Unable to convert links strings to binary path!"); tag->status = PLCTAG_ERR_BAD_PARAM; break; } /* * check the tag name, this is protocol specific. */ if(check_tag_name(tag, attr_get_str(attribs,"name","NONE")) != PLCTAG_STATUS_OK) { pdebug(debug,"Bad tag name!"); tag->status = PLCTAG_ERR_BAD_PARAM; break; } /* * add the tag to the session's list. */ if(session_add_tag_unsafe(tag, tag->session) != PLCTAG_STATUS_OK) { pdebug(debug,"unable to add new tag to connection!"); tag->status = PLCTAG_ERR_CREATE; break; } } pdebug(debug,"Done."); return (plc_tag)tag; }