SNMP agent attached to SPI slave

Dependencies:   mbed

Revision:
0:2a53a4c3238c
Child:
2:25e12a7fe0aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lwip/core/snmp/private_mib.c	Mon Aug 13 15:07:40 2012 +0000
@@ -0,0 +1,1354 @@
+/*****************************************************************************
+*                   Copyright Field Electronics Ltd
+* File:             private_mib.c
+* Reference:        3000-A3600-SRC-private_mib
+* Content:          Header file for private MIB tree structures
+* Version:          1.6
+* System:           mbed gnu compiler
+* Target Hardware:  mbed LPC1768                                  
+* Amendment Record:    
+* Author:      L. Smith for all versions unless otherwise specified
+* Initial release
+* 0.1         23/11/11: L. Smith
+  Derived from snmp_structs.h by Christiaan Simons <christiaan.simons@axon.tv>
+* 0.2         28/11/11: L. Smith
+  Add f3k_cpu_version & f3k_mbed_version to scalar values 
+* 0.3         01/12/11: L. Smith
+  Replace lwIP SNMP_ENTERPRISE_ID by Field PEN - see http://www.iana.org/assignments/enterprise-numbers
+* 0.4         13/12/11: L. Smith
+  Increase function calls for number of I/O nodes to 32 
+* 0.5         21/12/11: L. Smith
+  Increase f3k_system nodes from 3 to 5
+* 0.6         22/12/11: L. Smith
+  Add f3k_comms_set_value() and f3k_comms_set_test() to enable UID change
+* 0.7         27/12/11: L. Smith
+  Add f3k_sys_set_value() and f3k_sys_set_test() to enable UID change
+* 0.8         29/12/11: L. Smith
+  Update f3k_sys_set_value() and f3k_sys_set_test() to enable net address change
+* 0.9         30/12/11: L. Smith
+  Read least sig. (alternate) bytes from I/O channels in snmp_get_f3k_IO_value()
+* 1.0         11/01/12: L. Smith
+  Add breaks in case statement to fix f3k_speed reporting error
+* 1.1         30/01/12: L. Smith
+  Add f3k_SPI_count as f3k_sys_object 5 before f3k_run_scan
+* 1.2         02/05/12: L. Smith
+  Change pointers for RTU unit ID from s32_t to u16_t
+* 1.3         19/06/12: L. Smith
+  Add f3k_IO_mask as R/W f3k_sys_object 7 - hex formatted string
+* 1.4         20/06/12: L. Smith
+  Add snmp_trh_addrs[4] as R/W f3k_comms 8 - trap host SNMP_ASN1_IPADDR
+* 1.5         25/07/12: L. Smith
+  Add snmp_publiccommunity as 9th f3k_comms variable with R/W ability
+* 1.6         08/08/12: L. Smith
+  Add f3k_IO_alarm & f3k_al_mask nodes for I/O alarm strings
+*******************************************************************************/
+
+#include "lwip/opt.h"
+
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lwip/snmp.h"
+#include "lwip/udp.h"
+#include "lwip/snmp_asn1.h"
+#include "lwip/snmp_structs.h"
+#include "lwip/snmp_msg.h"
+#include "IO_file.h"
+#include "private_mib.h"
+
+/* mib_f3k integers derived from 3000 CPU */
+static u16_t f3k_error = 0,
+             f3k_num_cards = 0,
+             f3k_SPI_count = 0,
+             f3k_run_scan = 0,
+             f3k_uid = 0,
+             f3k_protocol = 0;
+static u32_t f3k_speed  = 0;
+static char f3k_fw_version[ 4 ] = {0,0,0,0};
+/* v1.3: I/O mask is read/written in SNMP protocol as 8 byte hex string */
+static char f3k_IO_mask[ 8 ] = {0,0,0,0,0,0,0,0};
+
+/* lengths of ethernet address strings */
+static u16_t snmp_ip_len = 0,
+             snmp_net_len = 0,
+             snmp_gwy_len = 0,
+             snmp_trh_len = 0,
+             snmp_dns_len = 0;
+/* ethernet address strings */
+static char snmp_ip_addrs[ 16 ] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static char snmp_net_mask[ 16 ] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static char snmp_gwy_addrs[ 16 ] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static char snmp_dns_addrs[ 16 ] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static char snmp_trh_addrs[ 16 ] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+//static char snmp_trh_addrs[ 4 ] = {0,0,0,0};    // v1.4: Trap host address
+
+
+static void f3k_amask_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void f3k_amask_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t f3k_amask_set_test(struct obj_def *od, u16_t len, void *value);
+static void f3k_amask_set_value(struct obj_def *od, u16_t len, void *value);
+static void f3k_alarm_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void f3k_alarm_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t f3k_alarm_set_test(struct obj_def *od, u16_t len, void *value);
+static void f3k_alarm_set_value(struct obj_def *od, u16_t len, void *value);
+static void f3k_IO_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void f3k_IO_get_value(struct obj_def *od, u16_t len, void *value);
+static void f3k_comms_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void f3k_comms_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t f3k_comms_set_test(struct obj_def *od, u16_t len, void *value);
+static void f3k_comms_set_value(struct obj_def *od, u16_t len, void *value);
+static void f3k_sys_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void f3k_sys_get_value(struct obj_def *od, u16_t len, void *value);
+static u8_t f3k_sys_set_test(struct obj_def *od, u16_t len, void *value);
+static void f3k_sys_set_value(struct obj_def *od, u16_t len, void *value);
+void snmp_get_f3k_data( void );
+u32_t snmp_get_f3k_IO_value( u8_t index );
+void snmp_update_net_addrs( void );
+int update_addrs_from_string( char * adrs_str, unsigned char * num_array );
+
+/* the following routines are not used as no tables are used for F3000  
+static void f3kentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);
+static void f3kentry_get_value(struct obj_def *od, u16_t len, void *value);
+
+// mib_f3k .1.3.6.1.4.1.SNMP_ENTERPRISE_ID 
+// index root node for f3kTable
+struct mib_list_rootnode f3k_root = {
+  &f3kentry_get_object_def,
+  &f3kentry_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_LR,
+  0,
+  NULL,
+  NULL,
+  0
+};
+
+const s32_t f3kentry_ids[2] = { 1, 2 };
+struct mib_node* const f3kentry_nodes[2] = {
+  (struct mib_node*)&f3k_root, (struct mib_node*)&f3k_root,
+};
+const struct mib_array_node f3kentry = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  2,
+  f3kentry_ids,
+  f3kentry_nodes
+};
+
+s32_t f3ktable_id = 1;
+struct mib_node* f3ktable_node = (struct mib_node*)&f3kentry;
+struct mib_ram_array_node f3ktable = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_RA,
+  0,
+  &f3ktable_id,
+  &f3ktable_node
+};
+*/
+
+/* f3k_al_mask nodes */
+const mib_scalar_node f3k_amask_scalar = {
+  &f3k_amask_get_object_def,
+  &f3k_amask_get_value,
+  &f3k_amask_set_test,
+  &f3k_amask_set_value,
+  MIB_NODE_SC,
+  0
+};
+
+const s32_t f3k_amask_ids[MAX_ALARM_ID] = { 1, 2, 3, 4, 5, 6, 7, MAX_ALARM_ID };
+struct mib_node* const f3k_amask_nodes[MAX_ALARM_ID] = {
+  (struct mib_node*)&f3k_amask_scalar, (struct mib_node*)&f3k_amask_scalar,
+  (struct mib_node*)&f3k_amask_scalar, (struct mib_node*)&f3k_amask_scalar,
+  (struct mib_node*)&f3k_amask_scalar, (struct mib_node*)&f3k_amask_scalar,
+  (struct mib_node*)&f3k_amask_scalar, (struct mib_node*)&f3k_amask_scalar
+};
+
+/* v1.6: f3k_al_mask .1.3.6.1.4.1.SNMP_ENTERPRISE_ID.mib_f3k */
+const struct mib_array_node f3k_al_mask = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  MAX_ALARM_ID,
+  f3k_amask_ids,
+  f3k_amask_nodes
+};
+
+
+/* f3k_IO_alarm nodes */
+const mib_scalar_node f3k_alarm_scalar = {
+  &f3k_alarm_get_object_def,
+  &f3k_alarm_get_value,
+  &f3k_alarm_set_test,
+  &f3k_alarm_set_value,
+  MIB_NODE_SC,
+  0
+};
+
+const s32_t f3k_alarm_ids[MAX_ALARM_ID] = { 1, 2, 3, 4, 5, 6, 7, MAX_ALARM_ID };
+struct mib_node* const f3k_alarm_nodes[MAX_ALARM_ID] = {
+  (struct mib_node*)&f3k_alarm_scalar, (struct mib_node*)&f3k_alarm_scalar,
+  (struct mib_node*)&f3k_alarm_scalar, (struct mib_node*)&f3k_alarm_scalar,
+  (struct mib_node*)&f3k_alarm_scalar, (struct mib_node*)&f3k_alarm_scalar,
+  (struct mib_node*)&f3k_alarm_scalar, (struct mib_node*)&f3k_alarm_scalar
+};
+
+/* v1.6: f3k_IO_alarm .1.3.6.1.4.1.SNMP_ENTERPRISE_ID.mib_f3k */
+const struct mib_array_node f3k_IO_alarm = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  MAX_ALARM_ID,
+  f3k_alarm_ids,
+  f3k_alarm_nodes
+};
+
+
+/* f3k_IO nodes */
+const mib_scalar_node f3k_IO_scalar = {
+  &f3k_IO_get_object_def,
+  &f3k_IO_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_SC,
+  0
+};
+
+const s32_t f3k_IO_ids[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 
+                               9, 10, 11, 12, 13, 14, 15, 16, 
+                               17, 18, 19, 20, 21, 22, 23, 24,
+                               25, 26, 27, 28, 29, 30, 31, 32 };
+struct mib_node* const f3k_IO_nodes[32] = {
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar,
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar, 
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar,
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar, 
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar,
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar, 
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar,
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar, 
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar,
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar, 
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar,
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar, 
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar,
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar, 
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar,
+  (struct mib_node*)&f3k_IO_scalar, (struct mib_node*)&f3k_IO_scalar
+};
+/* v0.3: f3k_IO .1.3.6.1.4.1.SNMP_ENTERPRISE_ID.mib_f3k */
+const struct mib_array_node f3k_IO = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  32,
+  f3k_IO_ids,
+  f3k_IO_nodes
+};
+
+
+/* f3k_comms nodes */
+const mib_scalar_node f3k_comms_scalar = {
+  &f3k_comms_get_object_def,
+  &f3k_comms_get_value,
+  &f3k_comms_set_test,
+  &f3k_comms_set_value,
+  MIB_NODE_SC,
+  0
+};
+
+const s32_t f3k_comms_ids[MAX_COMMS_ID] = { 1, 2, 3, 4, 5, 6, 7, 8, MAX_COMMS_ID };
+struct mib_node* const f3k_comms_nodes[MAX_COMMS_ID] = {
+  (struct mib_node*)&f3k_comms_scalar, (struct mib_node*)&f3k_comms_scalar,
+  (struct mib_node*)&f3k_comms_scalar, (struct mib_node*)&f3k_comms_scalar,
+  (struct mib_node*)&f3k_comms_scalar, (struct mib_node*)&f3k_comms_scalar,
+  (struct mib_node*)&f3k_comms_scalar, (struct mib_node*)&f3k_comms_scalar,
+  (struct mib_node*)&f3k_comms_scalar
+};
+/* v0.3: f3k_comms .1.3.6.1.4.1.SNMP_ENTERPRISE_ID.mib_f3k */
+const struct mib_array_node f3k_comms = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  MAX_COMMS_ID,
+  f3k_comms_ids,
+  f3k_comms_nodes
+};
+
+
+/* f3k_system nodes */
+const mib_scalar_node f3k_sys_scalar = {
+  &f3k_sys_get_object_def,
+  &f3k_sys_get_value,
+  &f3k_sys_set_test,
+  &f3k_sys_set_value,
+  MIB_NODE_SC,
+  0
+};
+
+const s32_t f3k_sys_ids[7] = { 1, 2, 3, 4, 5, 6, 7 };
+struct mib_node* const f3k_sys_nodes[7] = {
+  (struct mib_node*)&f3k_sys_scalar, (struct mib_node*)&f3k_sys_scalar,
+  (struct mib_node*)&f3k_sys_scalar, (struct mib_node*)&f3k_sys_scalar,
+  (struct mib_node*)&f3k_sys_scalar, (struct mib_node*)&f3k_sys_scalar,
+  (struct mib_node*)&f3k_sys_scalar 
+  /*, (struct mib_node*)&f3ktable */
+};
+/* v0.3: f3k_system .1.3.6.1.4.1.SNMP_ENTERPRISE_ID.mib_f3k */
+const struct mib_array_node f3k_system = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  7,
+  f3k_sys_ids,
+  f3k_sys_nodes
+};
+
+/* 1.6  Add f3k_IO_alarm & f3k_al_mask nodes for I/O alarm strings */
+const s32_t f3k_ids[5] = { 1, 2, 3, 4, 5 };
+struct mib_node* const f3k_nodes[5] = {
+  (struct mib_node*)&f3k_system,
+  (struct mib_node*)&f3k_comms,
+  (struct mib_node*)&f3k_IO,
+  (struct mib_node*)&f3k_IO_alarm,
+  (struct mib_node*)&f3k_al_mask
+};
+/* v0.3: mib_f3k .1.3.6.1.4.1.SNMP_ENTERPRISE_ID */
+/* f3k private node called from mib_array_node mib_link */
+const struct mib_array_node mib_f3k = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  5,
+  f3k_ids,
+  f3k_nodes
+};
+
+
+/* link from enterprises node to SNMP system calls via mib_private */
+/* v0.2: SNMP_ENTERPRISE_ID .1.3.6.1.4.1 
+const s32_t private_ids[1] = { SNMP_ENTERPRISE_ID };
+struct mib_node* const private_nodes[1] = { (struct mib_node*)&mib_f3k };
+const struct mib_array_node mib_enterprise = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  1,
+  private_ids,
+  private_nodes
+};
+*/
+
+/* internet .1.3.6.1 */
+/* When using a private MIB, you have to create a file 'private_mib.h' that contains
+ * a 'struct mib_array_node mib_private' which contains your MIB. 
+s32_t internet_ids[2] = { 2, 4 };
+struct mib_node* const internet_nodes[2] = { (struct mib_node*)&mgmt, (struct mib_node*)&mib_private };
+const struct mib_array_node internet = {
+  &noleafs_get_object_def,
+  &noleafs_get_value,
+  &noleafs_set_test,
+  &noleafs_set_value,
+  MIB_NODE_AR,
+  2,
+  internet_ids,
+  internet_nodes
+};
+*/
+
+
+/****************************************************************************/ 
+/*              snmp_get_f3k_data: 
+* Description:  Updates SNMP data from data array written by F3000 SPI
+*               Called by f3k_sys_get_value()
+* Parameters:   NONE
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+void snmp_get_f3k_data(void)
+{
+u8_t comm_cfg;
+u8_t f3k_version;
+
+  f3k_error = fsvr.get_error();
+  f3k_num_cards = (u16_t)fsvr.get_byte( NUM_CARD_IDX );
+  f3k_SPI_count = fsvr.get_SPI_count();
+  f3k_run_scan = (u16_t)fsvr.get_byte( RUN_SCAN_IDX );
+  strncpy( f3k_IO_mask, get_hex_mask( mask4_IO_registers ), 8 );  // v1.3: copy mask4_IO_registers as hex
+  f3k_uid  = (u16_t)fsvr.get_byte( UNIT_ID_IDX );
+  comm_cfg  = (u8_t)fsvr.get_byte( COMMS_IDX );
+  f3k_protocol  = (u16_t)(comm_cfg / 16);
+  switch (comm_cfg & 0x0f)
+  {
+      case    2    :  
+          f3k_speed  = 600;
+          break;
+      case    3    : 
+          f3k_speed  = 1200;
+          break;
+      case    4    : 
+          f3k_speed  = 2400;
+          break;
+      case    5    : 
+          f3k_speed  = 4800;
+          break;
+      case    6    : 
+          f3k_speed  = 9600;
+          break;
+      case    7    : 
+          f3k_speed  = 19200;
+          break;
+      case    8    : 
+          f3k_speed  = 38400;
+          break;
+      case    9    : 
+          f3k_speed  = 76800;
+          break;
+      default    : 
+          f3k_speed  = 9600;
+          break;
+  }
+  f3k_version = (u8_t)fsvr.get_byte( VERSION_IDX );
+  f3k_fw_version[0] = (f3k_version / 16) + '0'; 
+  f3k_fw_version[1] = '.';
+  if ( (f3k_version & 0xf) < 0xa )
+  {
+    f3k_fw_version[2] = (f3k_version & 0xf) + '0';
+  }
+  else 
+  {
+    f3k_fw_version[2] = (f3k_version & 0xf) - 0xa + 'A';
+  }
+}
+
+/****************************************************************************/ 
+/*              snmp_get_f3k_IO_value: 
+* Description:  Updates SNMP data from I/O data in array written by F3000 SPI
+*               Called by f3kentry_get_value()
+* Parameters:   IN: u8_t 1-based index into 0-based Field SPI server array
+* Returns:      u32_t io_value from Field SPI server array
+*/
+/****************************************************************************/ 
+u32_t snmp_get_f3k_IO_value( u8_t index )
+{
+unsigned short io_value;
+
+  index = index > 0 ?  2 * (index - 1) : index; // index range is 1 to 32
+  io_value = 256 * fsvr.get_byte( index );  // v0.9: read ms byte from I/O
+  io_value += fsvr.get_byte( index + 1 );   // v0.9: add ls byte from I/O
+  return (u32_t)io_value; 
+}
+
+/****************************************************************************/ 
+/*              snmp_update_net_addrs: 
+* Description:  Updates SNMP address strings from ethernet addresses
+*               v1.4: Add trap host address conversion
+*               Called by f3k_comms_get_object_def()
+* Parameters:   NONE
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+void snmp_update_net_addrs( void )
+{
+char i;
+
+  for ( i = 0; i < 16; i++ )
+  {                                 // ensure string terminated by 0
+    snmp_ip_addrs[ i ] = 0;
+    snmp_net_mask[ i ] = 0;
+    snmp_gwy_addrs[ i ] = 0;
+    snmp_dns_addrs[ i ] = 0;
+    snmp_trh_addrs[ i ] = 0;
+  }
+  sprintf( snmp_ip_addrs, "%d.%d.%d.%d", ip_ad[0], ip_ad[1], ip_ad[2], ip_ad[3] );
+  snmp_ip_len = strlen( snmp_ip_addrs );
+  sprintf( snmp_net_mask, "%d.%d.%d.%d", msk_ad[0], msk_ad[1], msk_ad[2], msk_ad[3] );
+  snmp_net_len = strlen( snmp_net_mask );
+  sprintf( snmp_gwy_addrs, "%d.%d.%d.%d", gwy_ad[0], gwy_ad[1], gwy_ad[2], gwy_ad[3] );
+  snmp_gwy_len = strlen( snmp_gwy_addrs );
+  sprintf( snmp_dns_addrs, "%d.%d.%d.%d", dns_ad[0], dns_ad[1], dns_ad[2], dns_ad[3] );
+  snmp_dns_len = strlen( snmp_dns_addrs );
+  sprintf( snmp_trh_addrs, "%d.%d.%d.%d", th_ad[0], th_ad[1], th_ad[2], th_ad[3] );
+  snmp_trh_len = strlen( snmp_trh_addrs );  
+/*  for ( i = 0; i < 4; i++ )
+  {                                 // copy IP addresses to string
+    snmp_trh_addrs[ i ] = th_ad[ i ];
+  } */
+}
+
+/****************************************************************************/ 
+/*              update_addrs_from_string: 
+* Description:  Reads data from adrs_str into num_array
+* Globals used: NONE 
+* Parameters:   IN: char * adrs_str
+*               OUT: unsigned char * num_array
+* Returns:      Returns set_ok = 1 if able to set value, 0 otherwise
+*/
+/****************************************************************************/ 
+int update_addrs_from_string( char * adrs_str, unsigned char * num_array )
+{
+unsigned char c, i, j, digit_found, number_completed;
+int set_ok, new_num;
+
+  set_ok = 1;                       // default is good value
+  new_num = 0;
+  i = j = 0;
+  number_completed = digit_found = false;
+  while ( ((c = adrs_str[ i ]) != 0) && (i++ < 16) )
+  {
+      num_array[ j ] = 0;
+      if ( c < '0' || c > '9' )
+      {                             // not a numeric character
+        if ( digit_found )
+        {
+          number_completed = true;
+        }
+      }
+      else                          // numeric character
+      {
+        digit_found = true;
+        if ( number_completed )
+        {                           // test for valid data
+          if ( (new_num <= 255) && (j < 4) )
+          {                         // save number into array
+            num_array[ j++ ] = new_num;
+          }
+          else
+          {
+            set_ok = 0;
+            break;
+          }
+          new_num = 0;
+        }
+        new_num = 10*new_num + c - '0';
+        number_completed = false;
+      } // else numeric character
+  } // end while
+  if ( number_completed || (c == 0) )
+  {                                 // test for valid data
+      if ( (new_num <= 255) && (j < 4) && (i <= 16) )
+      {                             // save last number into array
+        num_array[ j ] = new_num;
+      }
+      else
+      {
+        set_ok = 0;
+      }
+  }
+  return set_ok;  
+}
+
+
+/****************************************************************************/ 
+/*              f3k_sys_get_object_def: 
+* Description:  get definition for F3000 scalar objects
+*               Called via mib_scalar_node f3k_sys_scalar
+* Parameters:   IN: u8_t ident_len - length of ID in...
+*               IN: s32_t *ident - array holding ID
+*               OUT: struct obj_def *od - object definition found
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_sys_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+u8_t id;
+
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 7));
+  if ((ident_len == 2) &&
+      (ident[0] > 0) && (ident[0] <= MAX_PRIVATE_ID))
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    id = (u8_t)ident[0];
+//    printf("\r\nf3k_sys_get_object_def: ident_len %d, id %d\r\n", ident_len, id);
+    switch (id)
+    {
+      case 1: /* f3k_fw_version */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = 3; 
+        break;
+      case 2: /* snmp_fw_version */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = 4; 
+        break;
+      case 3: /* f3k_error */
+      case 4: /* f3k_num_cards */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(u32_t);
+        break;
+      case 5: /* f3k_SPI_count */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);
+        od->v_len = sizeof(u32_t);
+        break;
+      case 6: /* f3k_run_scan */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(u32_t);
+        break;
+      case 7: /* v1.3: f3k_IO_mask */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = 8; 
+        break;
+    } // end switch
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("f3k_sys_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+/****************************************************************************/ 
+/*              f3k_sys_get_value: 
+* Description:  Returns f3k scalar object value
+*               @param ident points to objectname.0 (object id trailer)
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes)
+*               OUT: void *value - points to (varbind) space to copy value into
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_sys_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u32_t *uint_ptr = (u32_t*)value;
+  u8_t *uchr_ptr = (u8_t*)value;
+  u8_t id;
+  u8_t i = 0;               // character pointer for copying unterminated strings
+
+  LWIP_UNUSED_ARG(len);
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_PRIVATE_ID));
+  snmp_get_f3k_data();                  // read the data from the SPI array
+  id = (u8_t)od->id_inst_ptr[0];
+  switch ( id )
+  {
+    case 1: /* f3k_fw_version */
+      while (i < len) {
+        *(uchr_ptr++) = f3k_fw_version[ i++ ];
+      }
+      break;
+    case 2: /* snmp_fw_version */
+      while (i < len) {
+        *(uchr_ptr++) = snmp_fw_version[ i++ ];
+      }
+      break;
+    case 3: /* f3k_error */
+      *uint_ptr = f3k_error;
+      break;
+    case 4: /* f3k_num_cards */
+      *uint_ptr = f3k_num_cards;
+      break;
+    case 5: /* f3k_SPI_count */
+      *uint_ptr = f3k_SPI_count;
+      break;
+    case 6: /* f3k_run_scan */
+      *uint_ptr = f3k_run_scan;
+      break;
+    case 7: /* v1.3: f3k_IO_mask */
+      while (i < len) {
+        *(uchr_ptr++) = f3k_IO_mask[ i++ ];
+      }
+      break;
+  }
+}
+
+/****************************************************************************/ 
+/*              f3k_sys_set_test: 
+* Description:  Test f3k_ object value before setting
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes) - NOT USED
+*               OUT: void *value - points to (varbind) space to copy value from
+* Returns:      Returns set_ok = 1 if able to set value, 0 otherwise
+*/
+/****************************************************************************/ 
+static u8_t
+f3k_sys_set_test(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t id, set_ok;
+  u8_t i = 0;               
+  u8_t * uc_ptr  = (u8_t*)value;        // char pointer to first byte in value
+  
+  LWIP_UNUSED_ARG(len);
+  set_ok = 0;
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 7));
+  id = (u8_t)od->id_inst_ptr[0];
+//  printf("\r\nf3k_sys_set_test:  id %d\r\n", id);
+  if ( id == 6 )
+  {                                 /* f3k_run_scan */
+    s32_t *sint_ptr = (s32_t*)value;
+
+    if ( (*sint_ptr == 0) || (*sint_ptr == 1) )
+    {
+        set_ok = 1;
+    }
+  }
+  else if ( id == 7 )
+  {                                 /* v1.3: f3k_IO_mask */
+    if ( len <= 8 )
+    {                               // ensure all digits are hexadecimal
+        set_ok = 1;
+        for ( i = 0; i < len; i++ )
+        {
+          if ( !isxdigit( *(uc_ptr++) ) )
+          {
+            set_ok = 0;             // invalid hexadecimal digit
+            break;                  // so quit
+          }
+        } 
+    }
+  }
+  return set_ok;
+}
+
+/****************************************************************************/ 
+/*              f3k_sys_set_value: 
+* Description:  Returns f3k scalar object value
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes) - NOT USED
+*               OUT: void *value - points to (varbind) space to copy value from
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_sys_set_value(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t id;
+  u8_t * uc_ptr  = (u8_t*)value;        // char pointer to first byte in value
+
+//  LWIP_UNUSED_ARG(len);
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 7));
+  id = (u8_t)od->id_inst_ptr[0];
+  if ( id == 6 )
+  {                                     /* f3k_run_scan */
+    cmd_buf[ RUN_SCAN_CMD ] = *uc_ptr;
+    cmd_buf[ 0 ] = cmd_buf[ RUN_SCAN_CMD ];  // tell the 3000 cpu  data available
+    new_cmd_idx = RUN_SCAN_CMD;
+    fsvr.put_byte( RUN_SCAN_IDX, cmd_buf[ RUN_SCAN_CMD ] );
+  }
+  else if ( id == 7 )
+  {                                     /* v1.3: f3k_IO_mask */
+    mask4_IO_registers = convert2decimal( uc_ptr, len );
+    net_addrs_set = true;               // save mask to file system
+  }
+}
+
+
+/****************************************************************************/ 
+/*              f3k_comms_get_object_def: 
+* Description:  get definition for F3000 scalar objects
+*               Called via mib_scalar_node f3k_comms_scalar
+* Parameters:   IN: u8_t ident_len - length of ID in...
+*               IN: s32_t *ident - array holding ID
+*               OUT: struct obj_def *od - object definition found
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_comms_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+u8_t id;
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+  if ((ident_len == 2) &&
+      (ident[0] > 0) && (ident[0] <= MAX_COMMS_ID)) // v1.5: change from MAX_PRIVATE_ID
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+    id = (u8_t)ident[0];
+//    printf("\r\nf3k_comms_get_object_def: ident_len %d, id %d\r\n", ident_len, id);
+    snmp_update_net_addrs();
+    switch (id)
+    {
+      case 1: /* RTU unit ID */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(u16_t);      // v1.2: changed from u32_t
+        break;
+      case 2: /* RTU baud rate */
+      case 3: /* RTU protocol */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_ONLY;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);
+        od->v_len = sizeof(u16_t);      // v1.2: changed from u32_t
+        break;
+      case 4: /* IP address */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = snmp_ip_len; 
+        break;
+      case 5: /* net mask */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = snmp_net_len; 
+        break;
+      case 6: /* Gateway address */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = snmp_gwy_len; 
+        break;
+      case 7: /* DNS address */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = snmp_dns_len; 
+        break;
+      case 8: /* v1.4: Trap host address */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = snmp_trh_len; 
+        break;
+       case 9: /* v1.5: community string */
+        od->instance = MIB_OBJECT_SCALAR;
+        od->access = MIB_OBJECT_READ_WRITE;
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+        od->v_len = strlen(snmp_publiccommunity); 
+        break;
+   }  // end switch
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("f3k_comms_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+/****************************************************************************/ 
+/*              f3k_comms_get_value: 
+* Description:  Returns f3k scalar object value
+*               @param ident points to objectname.0 (object id trailer)
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes)
+*               OUT: void *value - points to (varbind) space to copy value into
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_comms_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u32_t *uint_ptr = (u32_t*)value;
+  u8_t * uchr_ptr = (u8_t*)value;
+  u8_t id;
+  u8_t i = 0;
+
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_COMMS_ID));
+  snmp_get_f3k_data();                  // read the data from the SPI array
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 1: /* RTU unit ID */
+      *uint_ptr = f3k_uid;
+      break;
+    case 2: /* RTU baud rate */
+      *uint_ptr = f3k_speed;
+      break;
+    case 3: /* RTU protocol */
+      *uint_ptr = f3k_protocol;
+      break;
+    case 4: /* IP address */
+      while (i < len) {
+        *(uchr_ptr++) = snmp_ip_addrs[ i++ ];
+      }
+      break;
+    case 5: /* net mask */
+      while (i < len) {
+        *(uchr_ptr++) = snmp_net_mask[ i++ ];
+      }
+      break;
+    case 6: /* Gateway address */
+      while (i < len) {
+        *(uchr_ptr++) = snmp_gwy_addrs[ i++ ];
+      }
+      break;
+    case 7: /* DNS address */
+      while (i < len) {
+        *(uchr_ptr++) = snmp_dns_addrs[ i++ ];
+      }
+      break;
+    case 8: /* v1.4: Trap host address */
+      while (i < len) {
+        *(uchr_ptr++) = snmp_trh_addrs[ i++ ];
+      }
+    case 9: /* v1.5: community string */
+      while (i < len) {
+        *(uchr_ptr++) = snmp_publiccommunity[ i++ ];
+      }
+      break;
+  }
+}
+
+/****************************************************************************/ 
+/*              f3k_comms_set_test: 
+* Description:  Test f3k_comms object value before setting
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes) - NOT USED
+*               OUT: void *value - points to (varbind) space to copy value from
+* Returns:      Returns set_ok = 1 if able to set value, 0 otherwise
+*/
+/****************************************************************************/ 
+static u8_t
+f3k_comms_set_test(struct obj_def *od, u16_t len, void *value)
+{
+u8_t id, set_ok, i;
+u8_t * uc_ptr;
+u16_t *uint_ptr = (u16_t*)value;  // v1.2: changed from s32_t
+char test_addrs[16];
+unsigned char test_ad[4];
+
+  set_ok = i = 0;
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_COMMS_ID));
+  uc_ptr  = (u8_t*)value;               // char pointer to first byte in value
+  id = (u8_t)od->id_inst_ptr[0];
+//  printf("\r\nf3k_comms_set_test: id %d, len %d\r\n", id, len);
+  switch ( id ) 
+  {
+    case 1: /* RTU unit ID */
+      if ( *uint_ptr < 255 )
+      {
+        set_ok = 1;
+      }
+      break;
+    case 4: /* IP address */
+    case 5: /* net mask */
+    case 6: /* Gateway address */
+    case 7: /* DNS address */
+    case 8: /* v1.4: Trap host address */
+      if ( len <= 16 )
+      {
+        while ( i < 16 ) 
+        {
+          test_addrs[ i++ ] =  i < len ? *(uc_ptr++) : 0;
+        }
+        set_ok = update_addrs_from_string( test_addrs, test_ad );
+      }
+      break;
+    case 9: /* v1.5: community string */
+      if ( (len >= MIN_COMMUNITY) && (len < MAX_COMMUNITY) )
+      {
+        set_ok = 1;
+        while ( i++ < MAX_COMMUNITY ) 
+        {
+          if ( *(uc_ptr++) == ' ' )
+          {
+            set_ok = 0;             // no spaces allowed in community string
+          }
+        }
+      }
+      break;
+  }  // end switch
+  return set_ok;
+}
+
+/****************************************************************************/ 
+/*              f3k_comms_set_value: 
+* Description:  Returns f3k scalar object value
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes) - NOT USED
+*               OUT: void *value - points to (varbind) space to copy value from
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_comms_set_value(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t id, i;
+  u8_t * uc_ptr;
+
+  i = 0;
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_COMMS_ID));
+  uc_ptr  = (u8_t*)value;               // char pointer to first byte in value
+  id = (u8_t)od->id_inst_ptr[0];
+  switch (id)
+  {
+    case 1: /* RTU unit ID */
+      cmd_buf[ UNIT_ID_CMD ] = *uc_ptr;
+      cmd_buf[ 0 ] = cmd_buf[ UNIT_ID_CMD ]; // tell the 3000 cpu data available
+      new_cmd_idx = UNIT_ID_CMD;
+      fsvr.put_byte( UNIT_ID_IDX, cmd_buf[ UNIT_ID_CMD ] );
+      break;
+    case 4: /* IP address */
+      while ( i < 16 ) {
+        snmp_ip_addrs[ i++ ] = ( i < len ) ? *(uc_ptr++) : 0;
+      }
+      update_addrs_from_string( snmp_ip_addrs, ip_ad );
+      net_addrs_set = true;
+      break;
+    case 5: /* net mask */
+      while ( i < 16 ) {
+        snmp_net_mask[ i++ ] = ( i < len ) ? *(uc_ptr++) : 0;
+      }
+      update_addrs_from_string( snmp_net_mask, msk_ad );
+      net_addrs_set = true;
+      break;
+    case 6: /* Gateway address */
+      while ( i < 16 ) {
+        snmp_gwy_addrs[ i++ ] = ( i < len ) ? *(uc_ptr++) : 0;
+      }
+      update_addrs_from_string( snmp_gwy_addrs, gwy_ad );
+      net_addrs_set = true;
+      break;
+    case 7: /* DNS address */
+      while ( i < 16 ) {
+        snmp_dns_addrs[ i++ ] = ( i < len ) ? *(uc_ptr++) : 0;
+      }
+      update_addrs_from_string( snmp_dns_addrs, dns_ad );
+      net_addrs_set = true;
+      break;
+    case 8: /* v1.4: Trap host address */
+      while ( i < 16 ) {
+        snmp_trh_addrs[ i++ ] = ( i < len ) ? *(uc_ptr++) : 0;
+      }
+      update_addrs_from_string( snmp_trh_addrs, th_ad );
+      net_addrs_set = true;
+      break;
+    case 9: /* v1.5: community string */
+      while ( i < MAX_COMMUNITY ) {
+        snmp_publiccommunity[ i++ ] = ( i < len ) ? *(uc_ptr++) : 0;
+      }
+      net_addrs_set = true;
+      break;
+  }
+}
+
+
+/****************************************************************************/ 
+/*              f3k_IO_get_object_def: 
+* Description:  get definition for F3000 scalar objects
+*               Called via mib_scalar_node f3k_IO_scalar
+* Parameters:   IN: u8_t ident_len - length of ID in...
+*               IN: s32_t *ident - array holding ID
+*               OUT: struct obj_def *od - object definition found
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_IO_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+u8_t id;
+
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+  if ((ident_len == 2) &&
+      (ident[0] > 0) && (ident[0] <= MAX_IO_TABLE))
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    id = (u8_t)ident[0];
+    printf("\r\nf3k_IO_get_object_def: ident_len %d, id %d\r\n", ident_len, id);
+
+    od->instance = MIB_OBJECT_SCALAR;
+    od->access = MIB_OBJECT_READ_ONLY;
+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);
+    od->v_len = sizeof(u32_t);
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("f3k_IO_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+/****************************************************************************/ 
+/*              f3k_IO_get_value: 
+* Description:  Returns f3k scalar object value
+*               @param ident points to objectname.0 (object id trailer)
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes)
+*               OUT: void *value - points to (varbind) space to copy value into
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_IO_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u32_t *uint_ptr = (u32_t*)value;
+  u8_t id;
+
+  LWIP_UNUSED_ARG(len);
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff));
+  id = (u8_t)od->id_inst_ptr[0];
+  *uint_ptr = snmp_get_f3k_IO_value( id );
+}
+
+/****************************************************************************/ 
+/*              f3k_alarm_get_object_def: 
+* Description:  get definition for F3000 scalar objects
+*               Called via mib_scalar_node f3k_alarm_scalar
+* Parameters:   IN: u8_t ident_len - length of ID in...
+*               IN: s32_t *ident - array holding ID
+*               OUT: struct obj_def *od - object definition found
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_alarm_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+u8_t id;
+
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff));
+  if ((ident_len == 2) &&
+      (ident[0] > 0) && (ident[0] <= MAX_ALARM_ID)) 
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+    id = (u8_t)ident[0];
+    printf("\r\nf3k_alarm_get_object_def: ident_len %d, id %d\r\n", ident_len, id);
+    /* alarm strings */
+    od->instance = MIB_OBJECT_SCALAR;
+    od->access = MIB_OBJECT_READ_WRITE;
+    od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+    od->v_len = strlen( (const char *)alarm_msg[ id-1 ] ); 
+//    printf("f3k_alarm_get_object_def: od->v_len = strlen( get_alarm_string(id-1) ) %d\r\n", od->v_len);
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("f3k_alarm_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+/****************************************************************************/ 
+/*              f3k_alarm_get_value: 
+* Description:  Returns f3k scalar object value
+*               @param ident points to objectname.0 (object id trailer)
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes)
+*               OUT: void *value - points to (varbind) space to copy value into
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_alarm_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t * uchr_ptr = (u8_t*)value;
+  u8_t id;
+  u8_t i = 0;
+
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_ALARM_ID));
+  id = (u8_t)od->id_inst_ptr[0];
+//  printf("\r\nf3k_alarm_get_value: id %d, len %d", id, len );
+  while ( i < len ) {
+    *(uchr_ptr++) = (u8_t)alarm_msg[ id-1 ][ i++ ];
+  }
+}
+
+/****************************************************************************/ 
+/*              f3k_alarm_set_test: 
+* Description:  Test f3k_alarm object value before setting
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes) - NOT USED
+*               OUT: void *value - points to (varbind) space to copy value from
+* Returns:      Returns set_ok = 1 if able to set value, 0 otherwise
+*/
+/****************************************************************************/ 
+static u8_t
+f3k_alarm_set_test(struct obj_def *od, u16_t len, void *value)
+{
+u8_t id, set_ok;
+
+  LWIP_UNUSED_ARG(value);
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_ALARM_ID));
+  id = (u8_t)od->id_inst_ptr[0];
+  set_ok = (len > 0) && (len < MSG_LNGTH) ? 1 : 0;
+  printf("\r\f3k_alarm_set_test: id %d, len %d set_ok %d\r\n", id, len, set_ok);
+  return set_ok;
+}
+
+/****************************************************************************/ 
+/*              f3k_alarm_set_value: 
+* Description:  Sets f3k_alarm_scalar object value
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes) - NOT USED
+*               OUT: void *value - points to (varbind) space to copy value from
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_alarm_set_value(struct obj_def *od, u16_t len, void *value)
+{
+u8_t id, i;
+u8_t * uc_ptr;
+
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_ALARM_ID));
+  id = (u8_t)od->id_inst_ptr[0];
+  uc_ptr  = (u8_t*)value;               // char pointer to first byte in value
+  i = 0;
+//  printf("\r\f3k_alarm_set_value: id %d, len %d uc_ptr %c\r\n", id, len, *uc_ptr);
+  while ( i < MSG_LNGTH ) {
+    alarm_msg[id-1][i] = ( i < len ) ? *(uc_ptr++) : 0;
+    i++;
+  }
+  alarm_str_set = id;
+}
+
+/****************************************************************************/ 
+/*              f3k_amask_get_object_def: 
+* Description:  get definition for F3000 scalar objects
+*               Called via mib_scalar_node f3k_sys_scalar
+* Parameters:   IN: u8_t ident_len - length of ID in...
+*               IN: s32_t *ident - array holding ID
+*               OUT: struct obj_def *od - object definition found
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_amask_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)
+{
+u8_t id;
+
+  /* return to object name, adding index depth (1) */
+  ident_len += 1;
+  ident -= 1;
+  LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= MAX_ALARM_ID));
+  if ((ident_len == 2) &&
+      (ident[0] > 0) && (ident[0] <= MAX_ALARM_ID))
+  {
+    od->id_inst_len = ident_len;
+    od->id_inst_ptr = ident;
+
+    id = (u8_t)ident[0];
+    printf("\r\nf3k_amask_get_object_def: ident_len %d, id %d\r\n", ident_len, id);
+    od->instance = MIB_OBJECT_SCALAR;
+    od->access = MIB_OBJECT_READ_WRITE;
+    od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);
+    od->v_len = 8;                      // 8 hex chars mask IO channels 1-32
+  }
+  else
+  {
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("\nf3k_amask_get_object_def: no scalar\n"));
+    od->instance = MIB_OBJECT_NONE;
+  }
+}
+
+/****************************************************************************/ 
+/*              f3k_amask_get_value: 
+* Description:  Returns f3k_amask scalar object value
+*               @param ident points to objectname.0 (object id trailer)
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes)
+*               OUT: void *value - points to (varbind) space to copy value into
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_amask_get_value(struct obj_def *od, u16_t len, void *value)
+{
+  u8_t * uchr_ptr = (u8_t*)value;
+  u8_t id;
+  u8_t i = 0;
+
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_ALARM_ID));
+  id = (u8_t)od->id_inst_ptr[0];
+  strncpy( f3k_IO_mask, get_hex_mask( io_mask[id-1] ), 8 );  // v1.3: copy numeric io_mask[]
+  while ( i < len ) {
+    *(uchr_ptr++) = f3k_IO_mask[ i++ ];
+  }
+}
+
+/****************************************************************************/ 
+/*              f3k_amask_set_test: 
+* Description:  Test f3k_amask object value before setting
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes) - NOT USED
+*               OUT: void *value - points to (varbind) space to copy value from
+* Returns:      Returns set_ok = 1 if able to set value, 0 otherwise
+*/
+/****************************************************************************/ 
+static u8_t
+f3k_amask_set_test(struct obj_def *od, u16_t len, void *value)
+{
+u8_t i, id, set_ok;
+u8_t * uc_ptr  = (u8_t*)value;        // char pointer to first byte in value
+
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_ALARM_ID));
+  id = (u8_t)od->id_inst_ptr[0];
+  printf("\r\f3k_amask_set_test: id %d, len %d\r\n", id, len);
+  if ( (len > 0) && (len <= 8) )
+  {                                 // ensure all digits are hexadecimal
+    set_ok = 1;
+    for ( i = 0; i < len; i++ )
+    {
+      if ( !isxdigit( *(uc_ptr++) ) )
+      {
+        set_ok = 0;                 // invalid hexadecimal digit
+        break;                      // so quit
+      }
+    } 
+  }
+  return set_ok;
+}
+
+/****************************************************************************/ 
+/*              f3k_amask_set_value: 
+* Description:  Sets f3k_alarm_scalar object value
+* Parameters:   IN: struct obj_def *od - object definition found
+*               IN: u16_t len - return value space (in bytes) - NOT USED
+*               OUT: void *value - points to (varbind) space to copy value from
+* Returns:      NONE
+*/
+/****************************************************************************/ 
+static void
+f3k_amask_set_value(struct obj_def *od, u16_t len, void *value)
+{
+u8_t id;
+u8_t * uc_ptr  = (u8_t*)value;        // char pointer to first byte in value
+
+  LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= MAX_ALARM_ID));
+  id = (u8_t)od->id_inst_ptr[0];
+
+  io_mask[ id-1 ] = convert2decimal( uc_ptr, len );
+  alarm_str_set = id;
+}
+
+#endif /* LWIP_SNMP */