inline void hal_set_rst_low() { #if (RF230_BUS == 1) gpio_output_clear(GPIOA, 8); #else gpio_output_clear(GPIOB, 10); #endif }
// Initialize TX/RX state void init_tx_rx_state(void) { _tx_pin.port_index = GPIO_PORT_C; _tx_pin.pin_index = GPIO_PIN_19; _rx_pin.port_index = GPIO_PORT_B; _rx_pin.pin_index = GPIO_PIN_13; gpio_mux_configure(_tx_pin, GPIO_MUX_OUTPUT); gpio_mux_configure(_rx_pin, GPIO_MUX_OUTPUT); // By default, RX = always on and TX = enabled on demand gpio_output_clear(_tx_pin); gpio_output_clear(_rx_pin); log_debug("RS485: Initialized RS485 TX/RX state"); }
// Send Modbus packet int send_modbus_packet(uint8_t device_address, uint8_t sequence_number, Packet* packet_to_send) { int bytes_written = 0; uint16_t packet_crc16 = 0; uint8_t crc16_first_byte_index = 0; int packet_size = packet_to_send->header.length + MODBUS_PACKET_OVERHEAD; uint8_t modbus_packet[packet_size]; //printf(">>>>>>>>>>>>>>>>>>>>> SEN %llu\n", microseconds()); // Assemble Modbus packet header modbus_packet[0] = device_address; modbus_packet[1] = RS485_EXTENSION_MODBUS_FUNCTION_CODE; modbus_packet[2] = sequence_number; // Assemble Tinkerforge packet header memcpy(&modbus_packet[3], &packet_to_send->header, sizeof(PacketHeader)); // Assemble Tinkerforge packet payload (if any) memcpy(&modbus_packet[3+sizeof(PacketHeader)], &packet_to_send->payload, packet_to_send->header.length - TINKERFORGE_HEADER_LENGTH); // Calculating CRC16 packet_crc16 = crc16(modbus_packet, packet_to_send->header.length + MODBUS_PACKET_HEADER_LENGTH); // Assemble the calculated CRC16 to the Modbus packet crc16_first_byte_index = packet_to_send->header.length + MODBUS_PACKET_HEADER_LENGTH; modbus_packet[crc16_first_byte_index] = packet_crc16 >> 8; modbus_packet[++crc16_first_byte_index] = packet_crc16 & 0x00FF; // Enabling TX start = microseconds(); gpio_output_set(_tx_pin); // Sending packet bytes_written = write(_rs485_serial_fd, modbus_packet, sizeof(modbus_packet)); if (bytes_written <= 0) { // Disabling TX gpio_output_clear(_tx_pin); end = microseconds(); send_verify_flag = 0; log_error("RS485: Error sending packet through serial interface"); return -1; } // Save the packet as byte array memcpy(current_request_as_byte_array, modbus_packet, packet_size); // Start the send verify timer setup_timer(&send_verify_timer, TIME_UNIT_NSEC, SEND_VERIFY_TIMEOUT); timerfd_settime(_send_verify_event, 0, &send_verify_timer, NULL); // Set send verify flag send_verify_flag = 1; log_debug("RS485: Packet sent through serial interface"); return bytes_written; }
static void red_extension_configure_pin(ExtensionPinConfiguration *config, int extension) { gpio_mux_configure(config->pin[extension], config->mux); if (config->value == 0) { gpio_output_clear(config->pin[extension]); } else { gpio_output_set(config->pin[extension]); // This should enable pull-up in case of input } }
static void spi_radio_cs(uint8_t hi) { #if (RF230_BUS == 1) if (hi) { gpio_output_set(GPIOA, 4); } else { gpio_output_clear(GPIOA, 4); } #else #endif }
// Resets stack static void red_stack_reset(void) { // Change mux of reset pin to output gpio_mux_configure(_red_stack_reset_stack_pin, GPIO_MUX_OUTPUT); gpio_output_clear(_red_stack_reset_stack_pin); SLEEP_NS(0, 1000*1000*100); // Clear reset pin for 100ms to force reset gpio_output_set(_red_stack_reset_stack_pin); SLEEP_NS(1, 1000*1000*500); // Wait 1.5s so slaves can start properly // Change mux back to interrupt, so we can see if a human presses reset gpio_mux_configure(_red_stack_reset_stack_pin, GPIO_MUX_6); }
// Send verify timeout event handler void send_verify_timeout_handler(void *opaque) { (void)opaque; // Disabling TX gpio_output_clear(_tx_pin); end = microseconds(); // Disabling timers disable_all_timers(); // Clearing send verify flag send_verify_flag = 0; sent_ack_of_data_packet = 0; // Start slave poll timer in case of master if(_modbus_serial_config_address == 0 ) { master_current_request_processed = 1; master_poll_slave_timeout_handler(NULL); } log_error("RS485: Error sending packet on serial interface"); }
// Master retry event handler void master_retry_timeout_handler(void* opaque) { (void)opaque; // Turning off the timers disable_all_timers(); if(master_current_retry <= 0) { if(send_verify_flag) { // Disabling TX gpio_output_clear(_tx_pin); end = microseconds(); // Clearing send verify flag send_verify_flag = 0; } if(sent_current_request_from_queue) { queue_pop(&_rs485_extension.packet_to_modbus_queue, NULL); sent_current_request_from_queue = 0; } partial_receive_flag = 0; master_current_request_processed = 1; master_poll_slave_timeout_handler(NULL); return; } // Resend request partial_receive_flag = 0; master_current_request_processed = 0; send_modbus_packet(_rs485_extension.slaves[master_current_slave_to_process], current_sequence_number, ¤t_request); log_debug("RS485: Retrying to send current request"); // Decrease current retry master_current_retry --; // Start master retry timer setup_timer(&master_retry_timer, TIME_UNIT_NSEC, MASTER_RETRY_TIMEOUT); timerfd_settime(_master_retry_event, 0, &master_retry_timer, NULL); }
// New data available event handler void rs485_serial_data_available_handler(void* opaque) { (void)opaque; if(!send_verify_flag) { disable_all_timers(); } int bytes_received = 0; uint32_t uid_from_packet = 0; int add_recipient_opaque; Packet empty_packet; Packet data_packet; uint64_t dummy_read_buffer; // Merge or simply save the received bytes if(partial_receive_flag) { bytes_received = read(_rs485_serial_fd, &receive_buffer[partial_receive_merge_index], (RECEIVE_BUFFER_SIZE - partial_receive_merge_index)); printf("bytes_received %d\n", bytes_received); partial_receive_merge_index = partial_receive_merge_index + bytes_received; } else { partial_receive_merge_index = read(_rs485_serial_fd, receive_buffer, RECEIVE_BUFFER_SIZE); if (partial_receive_merge_index != 13) printf("partial_receive_merge_index %d\n", partial_receive_merge_index); } //log_info("PARTIAL_RECEIVE_MERGE_INDEX = %d", partial_receive_merge_index); // Checks at least 13 bytes is available in the receive buffer if(partial_receive_merge_index >= 13) { int packet_validation_code = is_valid_packet(receive_buffer, partial_receive_merge_index); switch(packet_validation_code) { case PACKET_SEND_VERIFY_OK: // Stop send verify timer if (read(_send_verify_event, &dummy_read_buffer, sizeof(uint64_t))) {} setup_timer(&send_verify_timer, TIME_UNIT_NSEC, 0); timerfd_settime(_send_verify_event, 0, &send_verify_timer, NULL); // Disabling TX gpio_output_clear(_tx_pin); end = microseconds(); // Clearing send verify flag send_verify_flag = 0; // Clearing partial receive flag partial_receive_flag = 0; if(sent_ack_of_data_packet) { sent_ack_of_data_packet = 0; master_current_request_processed = 1; master_poll_slave_timeout_handler(NULL); } log_debug("RS485: Send verified"); return; case PACKET_EMPTY_OK: // Proper empty packet log_debug("RS485: Empty packet received"); if(sent_current_request_from_queue){ queue_pop(&_rs485_extension.packet_to_modbus_queue, NULL); sent_current_request_from_queue = 0; } // Updating recipient in the routing table memcpy(&uid_from_packet, &receive_buffer[3], sizeof(uint32_t)); stack_add_recipient(&_rs485_extension.base, uid_from_packet, receive_buffer[0]); partial_receive_flag = 0; master_current_request_processed = 1; if(sent_ack_of_data_packet) { sent_ack_of_data_packet = 0; } master_poll_slave_timeout_handler(NULL); return; case PACKET_DATA_OK: // Proper data packet log_info("RS485: Data packet received"); // Send message into brickd dispatcher memset(&data_packet, 0, sizeof(Packet)); memcpy(&data_packet, &receive_buffer[3], partial_receive_merge_index - MODBUS_PACKET_OVERHEAD); network_dispatch_response(&data_packet); log_debug("RS485: Dispatched packet to network subsystem"); if(sent_current_request_from_queue){ queue_pop(&_rs485_extension.packet_to_modbus_queue, NULL); sent_current_request_from_queue = 0; } // Updating recipient in the routing table memcpy(&uid_from_packet, &receive_buffer[3], sizeof(uint32_t)); add_recipient_opaque = receive_buffer[0]; stack_add_recipient(&_rs485_extension.base, uid_from_packet, add_recipient_opaque); // Send ACK to the slave memset(&empty_packet, 0, sizeof(PacketHeader)); empty_packet.header.length = 8; send_modbus_packet(_rs485_extension.slaves[master_current_slave_to_process], current_sequence_number, &empty_packet); sent_ack_of_data_packet = 1; return; case PACKET_ERROR_SEND_VERIFY: // Retry the current request log_error("RS485: Send verify failed"); partial_receive_flag = 0; master_current_retry = MASTER_RETRIES; master_retry_timeout_handler(NULL); return; case PACKET_ERROR_ADDRESS: // Retry the current request log_error("RS485: Wrong address in packet"); partial_receive_flag = 0; master_current_retry = MASTER_RETRIES; master_retry_timeout_handler(NULL); return; case PACKET_ERROR_FUNCTION_CODE: log_error("RS485: Wrong function code in packet"); partial_receive_flag = 0; master_current_retry = MASTER_RETRIES; master_retry_timeout_handler(NULL); return; case PACKET_ERROR_SEQUENCE_NUMBER: // Retry the current request log_info("RS485: Wrong sequence number in packet"); partial_receive_flag = 0; master_current_retry = MASTER_RETRIES; master_retry_timeout_handler(NULL); return; case PACKET_ERROR_LENGTH: // Retry the current request log_error("RS485: Wrong length in packet"); partial_receive_flag = 0; master_current_retry = MASTER_RETRIES; master_retry_timeout_handler(NULL); return; case PACKET_ERROR_LENGTH_PARTIAL: log_debug("RS485: Partial data packet recieved"); handle_partial_receive(); return; case PACKET_ERROR_CRC16: // Retry the current request log_error("RS485: Wrong CRC16 in packet"); partial_receive_flag = 0; master_current_retry = MASTER_RETRIES; master_retry_timeout_handler(NULL); return; default: return; } } else { log_debug("RS485: Partial packet recieved"); handle_partial_receive(); return; } if(send_verify_flag) { // Disabling TX gpio_output_clear(_tx_pin); end = microseconds(); // Stop send verify timer if (read(_send_verify_event, &dummy_read_buffer, sizeof(uint64_t))) {} setup_timer(&send_verify_timer, TIME_UNIT_NSEC, 0); timerfd_settime(_send_verify_event, 0, &send_verify_timer, NULL); // Clearing send verify flag send_verify_flag = 0; } abort_current_request(); return; }
void api_led_on ( ) { gpio_output_clear ( GPIO_LED ); }
static int red_stack_init_spi(void) { uint8_t slave; const uint8_t mode = RED_STACK_SPI_CONFIG_MODE; const uint8_t lsb_first = RED_STACK_SPI_CONFIG_LSB_FIRST; const uint8_t bits_per_word = RED_STACK_SPI_CONFIG_BITS_PER_WORD; const uint32_t max_speed_hz = RED_STACK_SPI_CONFIG_MAX_SPEED_HZ; // Set Master High pin to low (so Master Bricks above RED Brick can // configure themselves as slave) gpio_mux_configure(_red_stack_master_high_pin, GPIO_MUX_OUTPUT); gpio_output_clear(_red_stack_master_high_pin); // Initialize slaves for (slave = 0; slave < RED_STACK_SPI_MAX_SLAVES; slave++) { _red_stack.slaves[slave].stack_address = slave; _red_stack.slaves[slave].status = RED_STACK_SLAVE_STATUS_ABSENT; _red_stack.slaves[slave].slave_select_pin = _red_stack_slave_select_pins[slave]; _red_stack.slaves[slave].sequence_number_master = 1; _red_stack.slaves[slave].sequence_number_slave = 0; // Bring slave in initial state (deselected) gpio_mux_configure(_red_stack.slaves[slave].slave_select_pin, GPIO_MUX_OUTPUT); red_stack_spi_deselect(&_red_stack.slaves[slave]); } // Reset slaves and wait for slaves to be ready red_stack_reset(); // Open spidev _red_stack_spi_fd = open(_red_stack_spi_device, O_RDWR); if (_red_stack_spi_fd < 0) { log_error("Could not open %s", _red_stack_spi_device); return -1; } if (ioctl(_red_stack_spi_fd, SPI_IOC_WR_MODE, &mode) < 0) { log_error("Could not configure SPI mode"); return -1; } if (ioctl(_red_stack_spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed_hz) < 0) { log_error("Could not configure SPI max speed"); return -1; } if (ioctl(_red_stack_spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0) { log_error("Could not configure SPI bits per word"); return -1; } if (ioctl(_red_stack_spi_fd, SPI_IOC_WR_LSB_FIRST, &lsb_first) < 0) { log_error("Could not configure SPI lsb first"); return -1; } // Create SPI packet transceive thread // FIXME: maybe handshake thread start? thread_create(&_red_stack_spi_thread, red_stack_spi_thread, NULL); return 0; }
static void red_stack_spi_select(REDStackSlave *slave) { gpio_output_clear(slave->slave_select_pin); }