Exemple #1
0
void read_eeprom(void)
{
   uint16_t addr, i;
   uint8_t len;
   uint8_t buf[64];
   uint8_t result;

   /*get address*/
   addr = mcs_recv();
   addr <<= 8;
   addr |= mcs_recv();

   /*get length*/
   len = mcs_recv();

   /*read eeprom*/
   result = i2c_eeprom_read(EEPROM_DEV, addr, buf, len);
  
   for(i=0; i<len; i++)
      mcs_send(buf[i]);

   if(result == EEPROM_OK)
      mcs_send(EEPROM_DONE);
   else
      mcs_send(BAD_EEPROM);
}
Exemple #2
0
int red_extension_read_ethernet_config(I2CEEPROM *i2c_eeprom, ExtensionEthernetConfig *ethernet_config) {
	if (i2c_eeprom_read(i2c_eeprom,
	                    EXTENSION_EEPROM_ETHERNET_MAC_ADDRESS,
	                    ethernet_config->mac,
	                    EXTENSION_ETHERNET_MAC_SIZE) < EXTENSION_ETHERNET_MAC_SIZE) {
		log_warn("Can't read MAC address, using default address");
		ethernet_config->mac[0] = 0x40;
		ethernet_config->mac[1] = 0xD8;
		ethernet_config->mac[2] = 0x55;
		ethernet_config->mac[3] = 0x02;
		ethernet_config->mac[4] = 0xA1;
		ethernet_config->mac[5] = 0x00;

		return -1;
	}

	return 0;
}
// Init function called from central brickd code
int rs485_extension_init(void) {
    uint8_t _tmp_eeprom_read_buf[4];
    int _eeprom_read_status;
    int phase = 0;
    
    log_info("RS485: Checking presence of extension");
    
    // Modbus config: TYPE
    _eeprom_read_status =
    i2c_eeprom_read((uint16_t)RS485_EXTENSION_MODBUS_CONFIG_LOCATION_TYPE,
                    _tmp_eeprom_read_buf, 4);
    if (_eeprom_read_status <= 0) {
        log_error("RS485: EEPROM read error. Most probably no RS485 extension present");
		return 0;
    }
    _modbus_serial_config_type = (uint32_t)((_tmp_eeprom_read_buf[0] << 0) |
                                 (_tmp_eeprom_read_buf[1] << 8) |
                                 (_tmp_eeprom_read_buf[2] << 16) |
                                 (_tmp_eeprom_read_buf[3] << 24));
        
    if (_modbus_serial_config_type == RS485_EXTENSION_TYPE) {

        log_info("RS485: Initializing extension subsystem");
        
        // Create base stack
        if(stack_create(&_rs485_extension.base, "rs485_extension",
                        (StackDispatchRequestFunction)rs485_extension_dispatch_to_modbus) < 0) {
            log_error("RS485: Could not create base stack for extension: %s (%d)",
                      get_errno_name(errno), errno);

            goto cleanup;
        }

        phase = 1;
        
        // Add to stacks array
        if(hardware_add_stack(&_rs485_extension.base) < 0) {
            goto cleanup;
        }

        phase = 2;
        
        // Initialize modbus packet queue
        if(queue_create(&_rs485_extension.packet_to_modbus_queue, sizeof(RS485ExtensionPacket)) < 0) {
            log_error("RS485: Could not create Modbus queue: %s (%d)",
                    get_errno_name(errno), errno);
            goto cleanup;
        }
        
        // Reading and storing eeprom config
        
        // Modbus config: ADDRESS
        _eeprom_read_status =
        i2c_eeprom_read((uint16_t)RS485_EXTENSION_MODBUS_CONFIG_LOCATION_ADDRESS,
                        _tmp_eeprom_read_buf, 4);
        if (_eeprom_read_status <= 0) {
            log_error("RS485: Could not read config ADDRESS from EEPROM");
            goto cleanup;
        }
        _modbus_serial_config_address = (uint32_t)((_tmp_eeprom_read_buf[0] << 0) |
                                        (_tmp_eeprom_read_buf[1] << 8) |
                                        (_tmp_eeprom_read_buf[2] << 16) |
                                        (_tmp_eeprom_read_buf[3] << 24));
                                        
        // Modbus config: BAUDRATE
        _eeprom_read_status = i2c_eeprom_read((uint16_t)RS485_EXTENSION_MODBUS_CONFIG_LOCATION_BAUDRATE,
                                              _tmp_eeprom_read_buf, 4);
        if (_eeprom_read_status <= 0) {
            log_error("RS485: Could not read config BAUDRATE from EEPROM");
            goto cleanup;
        }
        _modbus_serial_config_baudrate = (uint32_t)((_tmp_eeprom_read_buf[0] << 0) |
                                         (_tmp_eeprom_read_buf[1] << 8) |
                                         (_tmp_eeprom_read_buf[2] << 16) |
                                         (_tmp_eeprom_read_buf[3] << 24));
    
        // Modbus config: PARITY
        _eeprom_read_status = i2c_eeprom_read((uint16_t)RS485_EXTENSION_MODBUS_CONFIG_LOCATION_PARTIY,
                                              _tmp_eeprom_read_buf, 1);
        if (_eeprom_read_status <= 0) {
            log_error("RS485: Could not read config PARITY from EEPROM");
            goto cleanup;
        }
        if(_tmp_eeprom_read_buf[0] == RS485_EXTENSION_SERIAL_PARITY_NONE) {
            _modbus_serial_config_parity = RS485_EXTENSION_SERIAL_PARITY_NONE;
        }
        else if (_tmp_eeprom_read_buf[0] == RS485_EXTENSION_SERIAL_PARITY_EVEN){
            _modbus_serial_config_parity = RS485_EXTENSION_SERIAL_PARITY_EVEN;
        }
        else {
            _modbus_serial_config_parity = RS485_EXTENSION_SERIAL_PARITY_ODD;
        }
    
        // Modbus config: STOPBITS
        _eeprom_read_status =
        i2c_eeprom_read((uint16_t)RS485_EXTENSION_MODBUS_CONFIG_LOCATION_STOPBITS,
                        _tmp_eeprom_read_buf, 1);
        if (_eeprom_read_status <= 0) {
            log_error("RS485: Could not read config STOPBITS from EEPROM");
            goto cleanup;
        }
        _modbus_serial_config_stopbits = _tmp_eeprom_read_buf[0];

        // Modbus config (if master): SLAVE ADDRESSES
        if(_modbus_serial_config_address == 0) {
            _rs485_extension.slave_num = 0;
            uint16_t _current_eeprom_location =
            RS485_EXTENSION_MODBUS_CONFIG_LOCATION_SLAVE_ADDRESSES_START;
            uint32_t _current_slave_address;

            _rs485_extension.slave_num = 0;

            do {
                _eeprom_read_status = i2c_eeprom_read(_current_eeprom_location, _tmp_eeprom_read_buf, 4);
                if (_eeprom_read_status <= 0) {
                    log_error("RS485: Could not read config SLAVE ADDRESSES from EEPROM");
                    goto cleanup;
                }
                _current_slave_address = (uint32_t)((_tmp_eeprom_read_buf[0] << 0) |
                                         (_tmp_eeprom_read_buf[1] << 8) |
                                         (_tmp_eeprom_read_buf[2] << 16) |
                                         (_tmp_eeprom_read_buf[3] << 24));
        
                if(_current_slave_address != 0) {
                    _rs485_extension.slaves[_rs485_extension.slave_num] = _current_slave_address;
                    _rs485_extension.slave_num ++;
                }
                _current_eeprom_location = _current_eeprom_location + 4;
            }
            while(_current_slave_address != 0 
                  && 
                  _rs485_extension.slave_num < RS485_EXTENSION_MODBUS_MAX_SLAVES);
        }
        
        // Configuring serial interface from the configs
        if(rs485_extension_serial_init(RS485_EXTENSION_SERIAL_DEVICE) < 0) {
            goto cleanup;
        }
        
        // Initial RS485 TX/RX state
        init_tx_rx_state();
        
        phase = 3;

        // Setup partial data receive timer        
        setup_timer(&partial_receive_timer, TIME_UNIT_NSEC, PARTIAL_RECEIVE_TIMEOUT);
        _partial_receive_timeout_event = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
        
        if(!(_partial_receive_timeout_event < 0)) {
            if(event_add_source(_partial_receive_timeout_event, EVENT_SOURCE_TYPE_GENERIC,
                                EVENT_READ, partial_receive_timeout_handler, NULL) < 0) {
                log_error("RS485: Could not add partial receive timeout notification pipe as event source");
                goto cleanup;
            }
        }
        else {
            log_error("RS485: Could not create partial receive timer");
            goto cleanup;
        }

        phase = 4;

        // Adding serial data available event
        if(event_add_source(_rs485_serial_fd, EVENT_SOURCE_TYPE_GENERIC,
                            EVENT_READ, rs485_serial_data_available_handler, NULL) < 0) {
            log_error("RS485: Could not add new serial data event");
            goto cleanup;
        }

        phase = 5;

        // Setup master retry timer        
        setup_timer(&master_retry_timer, TIME_UNIT_NSEC, MASTER_RETRY_TIMEOUT);
        _master_retry_event = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
        
        if(!(_master_retry_event < 0)) {
            if(event_add_source(_master_retry_event, EVENT_SOURCE_TYPE_GENERIC,
                                EVENT_READ, master_retry_timeout_handler, NULL) < 0) {
                log_error("RS485: Could not add Modbus master retry notification pipe as event source");
                goto cleanup;
            }
        }
        else {
            log_error("RS485: Could not create Modbus master retry timer");
            goto cleanup;
        }

        phase = 6;

        // Setup send verify timer
        setup_timer(&send_verify_timer, TIME_UNIT_NSEC, SEND_VERIFY_TIMEOUT);
        _send_verify_event = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
        
        if(!(_send_verify_event < 0)) {
            if(event_add_source(_send_verify_event, EVENT_SOURCE_TYPE_GENERIC,
                                EVENT_READ, send_verify_timeout_handler, NULL) < 0) {
                log_error("RS485: Could not add Modbus send verify notification pipe as event source");
                goto cleanup;
            }
        }
        else {
            log_error("RS485: Could not create Modbus send verify timer");
            goto cleanup;
        }

        phase = 7;

        // Get things going in case of a master
        if(_modbus_serial_config_address == 0 && _rs485_extension.slave_num > 0) {
            // Setup master poll slave timer
            setup_timer(&master_poll_slave_timer, TIME_UNIT_NSEC, MASTER_POLL_SLAVE_TIMEOUT);
            _master_poll_slave_event = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
            if(!(_master_poll_slave_event < 0) ) {
                if(event_add_source(_master_poll_slave_event, EVENT_SOURCE_TYPE_GENERIC,
                                    EVENT_READ, master_poll_slave_timeout_handler, NULL) < 0) {
                    log_error("RS485: Could not add Modbus master poll slave notification pipe as event source");
                    goto cleanup;
                }
            }
            else {
                log_error("RS485: Could not create Modbus master poll slave timer");
                goto cleanup;
            }
            master_poll_slave_timeout_handler(NULL);
        }

        phase = 8;
        _initialized = true;
    }
    else {
        log_info("RS485: Extension not present");
        goto cleanup;
    }
    
    cleanup:
        switch (phase) { // no breaks, all cases fall through intentionally
            case 7:
                close(_send_verify_event);
                event_remove_source(_send_verify_event, EVENT_SOURCE_TYPE_GENERIC);
                
            case 6:
                close(_master_retry_event);
                event_remove_source(_master_retry_event, EVENT_SOURCE_TYPE_GENERIC);
            
            case 5:
                close(_rs485_serial_fd);
                event_remove_source(_rs485_serial_fd, EVENT_SOURCE_TYPE_GENERIC);

            case 4:
                close(_partial_receive_timeout_event);
                event_remove_source(_partial_receive_timeout_event, EVENT_SOURCE_TYPE_GENERIC);

            case 3:
                queue_destroy(&_rs485_extension.packet_to_modbus_queue, NULL);
                
            case 2:
                hardware_remove_stack(&_rs485_extension.base);

            case 1:
                stack_destroy(&_rs485_extension.base);

            default:
                break;
        }
    return phase == 8 ? 0 : -1;
}
Exemple #4
0
int red_extension_init(void) {
	uint8_t buf[4];
	int i, j, ret;
	ExtensionBaseConfig base_config[2];

	// First we remove the Ethernet Extension kernel module (if there is one)
	// to make sure that there isn't a collision between SPI select and I2C select.
	red_ethernet_extension_rmmod();

	// Then we deselect all EEPROMS
	for (i = 0; i < EXTENSION_NUM_MAX; i++) {
		for (j = 0; j < extension_startup.num_configs; j++) {
			red_extension_configure_pin(&extension_startup.config[j], i);
		}
	}

	// Now we can try to find the configurations
	for (i = 0; i < EXTENSION_NUM_MAX; i++) {
		I2CEEPROM i2c_eeprom;
		log_debug("Checking for presence of Extension at position %d", i);
		int eeprom_length = 0;
		uint8_t eeprom_buffer[EEPROM_SIZE];

		base_config[i].extension = i;
		base_config[i].type = EXTENSION_TYPE_NONE;

		if (i2c_eeprom_create(&i2c_eeprom, i) < 0) {
			return -1;
		}

		if ((eeprom_length = red_extension_read_eeprom_from_fs(eeprom_buffer, i)) > 2) {
			int start_addr = eeprom_buffer[0] | (eeprom_buffer[1] << 8);

			if (eeprom_length + start_addr >= EEPROM_SIZE) {
				log_warn("Found malformed EEPROM config (start=%d, length=%d) for extension %d",
				         start_addr, eeprom_length, i);
			} else {
				log_info("Found new EEPROM config (start=%d, length=%d) for extension %d",
				         start_addr, eeprom_length, i);

				if (i2c_eeprom_write(&i2c_eeprom, start_addr, eeprom_buffer+2, eeprom_length-2) < 0) {
					log_warn("Writing EEPROM config for extension %d failed", i);
				} else {
					log_debug("Wrote EEPROM config (start=%d, length=%d) for extension %d",
					          start_addr, eeprom_length, i);
				}
			}
		}

		if (i2c_eeprom_read(&i2c_eeprom,
		                    EXTENSION_EEPROM_TYPE_LOCATION,
		                    buf,
		                    EXTENSION_EEPROM_TYPE_SIZE) < EXTENSION_EEPROM_TYPE_SIZE) {
			log_info("Could not find Extension at position %d", i);

			continue;
		}

		base_config[i].type = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

		// If there is an extension that is either not configured (Extension type NONE)
		// Or that we currently don't support (WIFI), we will log it, but try to
		// continue finding extensions. We can support an extension at position 1 if
		// there is an unsupported extension at position 0.
		if (base_config[i].type == EXTENSION_TYPE_NONE) {
			log_warn("Could not find Extension at position %d (Type None)", i);
			continue;
		}

		if ((base_config[i].type != EXTENSION_TYPE_ETHERNET) && (base_config[i].type != EXTENSION_TYPE_RS485)) {
			log_warn("Extension at position %d not supported (type %d)", i, base_config[i].type);
			continue;
		}

		switch (base_config[i].type) {
		case EXTENSION_TYPE_RS485:
			ret = red_extension_read_rs485_config(&i2c_eeprom, (ExtensionRS485Config *) &base_config[i]);
			i2c_eeprom_destroy(&i2c_eeprom);

			if (ret < 0) {
				log_warn("Could not read RS485 config, ignoring extension at position %d", i);

				continue;
			}

			if (red_extension_save_rs485_config_to_fs((ExtensionRS485Config *) &base_config[i]) < 0) {
				log_warn("Could not save RS485 config. RS485 Extension at position %d will not show up in Brick Viewer", i);
			}

			break;

		case EXTENSION_TYPE_ETHERNET:
			ret = red_extension_read_ethernet_config(&i2c_eeprom, (ExtensionEthernetConfig *) &base_config[i]);
			i2c_eeprom_destroy(&i2c_eeprom);

			if (ret < 0) {
				log_warn("Could not read Ethernet config, ignoring extension at position %d", i);

				continue;
			}

			if (red_extension_save_ethernet_config_to_fs((ExtensionEthernetConfig *) &base_config[i]) < 0) {
				log_warn("Could not save Ethernet config. Ethernet Extension at position %d will not show up in Brick Viewer", i);
			}

			break;
		}
	}

	// Configure the pins and initialize extensions
	for (i = 0; i < EXTENSION_NUM_MAX; i++) {
		switch (base_config[i].type) {
		case EXTENSION_TYPE_RS485:
			log_info("Found RS485 Extension at position %d", i);

			for (j = 0; j < extension_rs485_pin_config.num_configs; j++) {
				red_extension_configure_pin(&extension_rs485_pin_config.config[j], i);
			}

			if (red_rs485_extension_init((ExtensionRS485Config *) &base_config[i]) < 0) {
				continue;
			}

			_red_extension_type[i] = EXTENSION_TYPE_RS485;
			break;

		case EXTENSION_TYPE_ETHERNET:
			log_info("Found Ethernet Extension at position %d", i);

			for (j = 0; j < extension_ethernet_pin_config.num_configs; j++) {
				red_extension_configure_pin(&extension_ethernet_pin_config.config[j], i);
			}

			if (red_ethernet_extension_init((ExtensionEthernetConfig *) &base_config[i]) < 0) {
				continue;
			}

			_red_extension_type[i] = EXTENSION_TYPE_ETHERNET;
			break;
		}
	}

	return 0;
}
Exemple #5
0
int red_extension_read_rs485_config(I2CEEPROM *i2c_eeprom, ExtensionRS485Config *rs485_config) {
	uint8_t buf[4];

	// Config: ADDRESS
	if (i2c_eeprom_read(i2c_eeprom, EXTENSION_EEPROM_RS485_ADDRESS_LOCATION, buf, 4) < 4) {
		log_error("RS485: Could not read config ADDRESS from EEPROM");

		return -1;
	}

	rs485_config->address = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

	// Config: BAUDRATE
	if (i2c_eeprom_read(i2c_eeprom, EXTENSION_EEPROM_RS485_BAUDRATE_LOCATION, buf, 4) < 4) {
		log_error("RS485: Could not read config BAUDRATE from EEPROM");

		return -1;
	}

	rs485_config->baudrate = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

	if (rs485_config->baudrate < 8) {
		log_error("RS485: Configured baudrate is too low");

		return -1;
	}

	// Config: PARITY
	if (i2c_eeprom_read(i2c_eeprom, EXTENSION_EEPROM_RS485_PARTIY_LOCATION, buf, 1) < 1) {
		log_error("RS485: Could not read config PARITY from EEPROM");

		return -1;
	}

	if (buf[0] == RS485_EXTENSION_SERIAL_PARITY_NONE) {
		rs485_config->parity = RS485_EXTENSION_SERIAL_PARITY_NONE;
	} else if (buf[0] == RS485_EXTENSION_SERIAL_PARITY_EVEN){
		rs485_config->parity = RS485_EXTENSION_SERIAL_PARITY_EVEN;
	} else {
		rs485_config->parity = RS485_EXTENSION_SERIAL_PARITY_ODD;
	}

	// Config: STOPBITS
	if (i2c_eeprom_read(i2c_eeprom, EXTENSION_EEPROM_RS485_STOPBITS_LOCATION, buf, 1) < 1) {
		log_error("RS485: Could not read config STOPBITS from EEPROM");

		return -1;
	}

	rs485_config->stopbits = buf[0];

	// Config (if master): SLAVE ADDRESSES
	if (rs485_config->address == 0) {
		rs485_config->slave_num = 0;
		uint16_t current_eeprom_location = EXTENSION_EEPROM_RS485_SLAVE_ADDRESSES_START_LOCATION;
		uint32_t current_slave_address;

		rs485_config->slave_address[0] = 0;

		while (rs485_config->slave_num < EXTENSION_RS485_SLAVES_MAX) {
			// Config: SLAVE ADDRESS

			if (i2c_eeprom_read(i2c_eeprom, current_eeprom_location, buf, 4) < 4) {
				log_error("RS485: Could not read config SLAVE ADDRESSES from EEPROM");
				return -1;
			}

			current_slave_address = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

			rs485_config->slave_address[rs485_config->slave_num] = current_slave_address;

			if (current_slave_address == 0) {
				break;
			}

			rs485_config->slave_num++;
			current_eeprom_location += 4;
		}
	} else {
		log_error("RS485: Only master mode supported");

		return -1;
	}

	return 0;
}
uint32_t send_data_stream_ble(ble_luxsync_t * p_luxsync, uint8_t fetchData, uint8_t init)
{
	static uint8_t databuffer[READ_LENGTH+10];
	static uint32_t currentPosition = 0;
	
	static uint32_t stopPosition = 0;
	static uint32_t remainingData = 0;
	static uint16_t read_length;
	uint32_t err_code = NRF_SUCCESS;
	static uint32_t endOfChunk = 0;
	static int x = 0;
		
	
	if ( init ) 
	{
		currentPosition = 0;
		stopPosition = eeprom_find_add_pointer();
		remainingData = 0;
	}
	
	if ( fetchData )
	{
		print("Getting more data\r\n");
		endOfChunk = currentPosition + READ_LENGTH * CHUNKS_PER_TRANSFER; 
	}
	
	if ( currentPosition < endOfChunk )
		fetchData = 1;
	
	do {
		
		if ( remainingData <= 0 && fetchData )
		{
			
			if ( (stopPosition - currentPosition) < READ_LENGTH )
				read_length = stopPosition - currentPosition;
			else
				read_length = READ_LENGTH;
			
			if ( !(i2c_eeprom_read(currentPosition,databuffer, read_length)) )
				 {
					 err_code = 0xDB; //Memory not read 
				 }
			else
				 {
					 print("*[%d]", currentPosition);
					 remainingData = read_length;
					 currentPosition += read_length;
				 }
			}	
		
			
		
print(".");		
		while(remainingData > 0 ) //< read_length)
		{

			err_code=ble_luxsync_write_update(p_luxsync,databuffer+(read_length-remainingData),WRITE_LENGTH);
			if ( err_code== NRF_SUCCESS||
					 err_code==BLE_ERROR_GATTS_SYS_ATTR_MISSING||
					 err_code==NRF_ERROR_INVALID_STATE) 
					{
					// Ignore error.
		//			m_remaining_data =(m_remaining_data+write_lenth);
						remainingData -= WRITE_LENGTH;
					}
					else if (err_code==BLE_ERROR_NO_TX_BUFFERS )
					{
						//print(".[%d]", remainingData);
					 break;
					}
					else 
					{
//					APP_ERROR_HANDLER(err_code);
														
					}	
		}
print("/");
		
		print("%d %d %d\r\n", currentPosition, endOfChunk, stopPosition);
	} while( currentPosition < endOfChunk && currentPosition < stopPosition && err_code != BLE_ERROR_NO_TX_BUFFERS );
print("E");

	
//		nrf_gpio_pin_set(MEMORY_LED_PIN_NO); /// debug
		
	//if (m_remaining_data>=read_length1)
	if ( currentPosition >= stopPosition ) 
	{
//		nrf_delay_ms(50);
		err_code = ble_luxsync_ACK_update(p_luxsync,0x04);   //•	Once all the data is sent it changes sync ACk to 0x04 indicating end of data stream
		
		if ( err_code== NRF_SUCCESS||
					 err_code==BLE_ERROR_GATTS_SYS_ATTR_MISSING||
					 err_code==NRF_ERROR_INVALID_STATE) 
					{
					// Ignore error.
						nrf_gpio_pin_set(MEMORY_LED_PIN_NO);
						flag_send_data=false;
						
						print("DONE transmitting\r\n");
						
						//timers_start();				
					}
/*					else if (err_code==BLE_ERROR_NO_TX_BUFFERS )
					{
		//			 break;
					}
					else 
					{
					APP_ERROR_HANDLER(err_code);
					}	 */
		
	}
 return err_code;
}
Exemple #7
0
int red_extension_read_rs485_config(I2CEEPROM *i2c_eeprom, ExtensionRS485Config *rs485_config) {
	uint8_t buf[4];

	// address
	if (i2c_eeprom_read(i2c_eeprom, EXTENSION_EEPROM_RS485_ADDRESS_LOCATION, buf, 4) < 4) {
		log_error("Could not read RS485 address from EEPROM");

		return -1;
	}

	rs485_config->address = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

	// baudrate
	if (i2c_eeprom_read(i2c_eeprom, EXTENSION_EEPROM_RS485_BAUDRATE_LOCATION, buf, 4) < 4) {
		log_error("Could not read RS485 baudrate from EEPROM");

		return -1;
	}

	rs485_config->baudrate = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

	if (rs485_config->baudrate < 8) {
		log_error("Configured RS485 baudrate is too low");

		return -1;
	}

	// parity
	if (i2c_eeprom_read(i2c_eeprom, EXTENSION_EEPROM_RS485_PARTIY_LOCATION, buf, 1) < 1) {
		log_error("Could not read RS485 parity from EEPROM");

		return -1;
	}

	if (buf[0] == RS485_EXTENSION_SERIAL_PARITY_NONE) {
		rs485_config->parity = RS485_EXTENSION_SERIAL_PARITY_NONE;
	} else if (buf[0] == RS485_EXTENSION_SERIAL_PARITY_EVEN){
		rs485_config->parity = RS485_EXTENSION_SERIAL_PARITY_EVEN;
	} else {
		rs485_config->parity = RS485_EXTENSION_SERIAL_PARITY_ODD;
	}

	// stopbits
	if (i2c_eeprom_read(i2c_eeprom, EXTENSION_EEPROM_RS485_STOPBITS_LOCATION, buf, 1) < 1) {
		log_error("Could not read RS485 stopbits from EEPROM");

		return -1;
	}

	rs485_config->stopbits = buf[0];

	// slave addresses
	if (rs485_config->address == 0) {
		rs485_config->slave_num = 0;
		uint16_t current_eeprom_location = EXTENSION_EEPROM_RS485_SLAVE_ADDRESSES_START_LOCATION;
		uint32_t current_slave_address;

		rs485_config->slave_address[0] = 0;

		while (rs485_config->slave_num < EXTENSION_RS485_SLAVES_MAX) {
			if (i2c_eeprom_read(i2c_eeprom, current_eeprom_location, buf, 4) < 4) {
				log_error("Could not read RS485 slave addresses from EEPROM");
				return -1;
			}

			current_slave_address = (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

			rs485_config->slave_address[rs485_config->slave_num] = current_slave_address;

			if (current_slave_address == 0) {
				break;
			}

			rs485_config->slave_num++;
			current_eeprom_location += 4;
		}
	}

	return 0;
}