├── .clang-format ├── .gitignore ├── COPYRIGHT-3DR ├── LICENSE-APACHE ├── Makefile ├── README.md ├── SOURCE ├── STM32Loader ├── checkArtooAndUpdate.py ├── checkArtooAndUpdateTest ├── reset_artoo ├── stm32_check_cal.py ├── stm32_readout_protect.py ├── stm32_reset.py ├── stm32_update_test.sh ├── test_save_stick_cal.sh └── updateArtoo.sh ├── config ├── checknet ├── configinit ├── logrotate-sololink.conf.controller ├── logrotate-sololink.conf.solo ├── max_dgram_qlen ├── sololink ├── sololink.orig ├── sololink_config ├── sololink_config_sample ├── sololink_config_test ├── syslog.conf.busybox.controller ├── syslog.conf.busybox.solo ├── test_3dr_README ├── test_3dr_controller │ ├── STM_VERSION │ ├── VERSION │ ├── etc │ │ ├── hostapd.conf │ │ └── hostapd.conf.md5 │ └── mnt │ │ └── rootfs.ro │ │ └── etc │ │ └── hostapd.orig ├── test_3dr_solo │ ├── PIX_VERSION │ ├── VERSION │ ├── etc │ │ ├── wpa_supplicant.conf │ │ └── wpa_supplicant.conf.md5 │ └── mnt │ │ └── rootfs.ro │ │ └── etc │ │ └── wpa_supplicant.orig └── test_configinit ├── flightcode ├── Makefile ├── arp_table │ ├── Makefile │ └── main.c ├── baudcheck │ ├── Makefile │ └── baudcheck.cpp ├── command │ ├── Commander.cpp │ ├── Commander.h │ └── Makefile ├── dataflash_logger │ ├── Makefile │ ├── MsgHandler.cpp │ ├── MsgHandler.h │ ├── analyzer_util.cpp │ ├── analyzer_util.h │ ├── analyzervehicle_copter.cpp │ ├── common_tool.cpp │ ├── common_tool.h │ ├── dataflash_logger.cpp │ ├── dataflash_logger.h │ ├── dataflash_logger_program.cpp │ ├── dataflash_logger_program.h │ ├── dataflash_message_handler.cpp │ ├── dataflash_message_handler.h │ ├── format_reader.cpp │ ├── format_reader.h │ ├── heart.cpp │ ├── heart.h │ ├── la-log.cpp │ ├── la-log.h │ ├── mavlink_message_handler.cpp │ ├── mavlink_message_handler.h │ ├── mavlink_reader.cpp │ ├── mavlink_reader.h │ ├── mavlink_writer.cpp │ ├── mavlink_writer.h │ ├── message_handler.cpp │ ├── message_handler.h │ ├── telem_client.cpp │ ├── telem_client.h │ ├── telem_forwarder_client.cpp │ ├── telem_forwarder_client.h │ ├── telem_serial.cpp │ └── telem_serial.h ├── dflog │ ├── Makefile │ ├── dataFlashMAVLink-to-artoo.py │ ├── dflog_downloader.cpp │ └── loadLog.py ├── hostapd_ctrl │ ├── Makefile │ └── main.c ├── ini │ ├── Makefile │ ├── cpp │ │ ├── INIReader.cpp │ │ ├── INIReader.h │ │ └── Makefile │ ├── ini.c │ └── ini.h ├── log │ ├── Log.cpp │ ├── Log.h │ └── Makefile ├── mavlink │ ├── c_library │ │ ├── ardupilotmega │ │ │ ├── ardupilotmega.h │ │ │ ├── mavlink.h │ │ │ ├── mavlink_msg_ahrs.h │ │ │ ├── mavlink_msg_ahrs2.h │ │ │ ├── mavlink_msg_ahrs3.h │ │ │ ├── mavlink_msg_airspeed_autocal.h │ │ │ ├── mavlink_msg_ap_adc.h │ │ │ ├── mavlink_msg_autopilot_version_request.h │ │ │ ├── mavlink_msg_battery2.h │ │ │ ├── mavlink_msg_camera_feedback.h │ │ │ ├── mavlink_msg_camera_status.h │ │ │ ├── mavlink_msg_compassmot_status.h │ │ │ ├── mavlink_msg_data16.h │ │ │ ├── mavlink_msg_data32.h │ │ │ ├── mavlink_msg_data64.h │ │ │ ├── mavlink_msg_data96.h │ │ │ ├── mavlink_msg_digicam_configure.h │ │ │ ├── mavlink_msg_digicam_control.h │ │ │ ├── mavlink_msg_ekf_status_report.h │ │ │ ├── mavlink_msg_fence_fetch_point.h │ │ │ ├── mavlink_msg_fence_point.h │ │ │ ├── mavlink_msg_fence_status.h │ │ │ ├── mavlink_msg_gimbal_control.h │ │ │ ├── mavlink_msg_gimbal_report.h │ │ │ ├── mavlink_msg_gimbal_torque_cmd_report.h │ │ │ ├── mavlink_msg_gopro_get_request.h │ │ │ ├── mavlink_msg_gopro_get_response.h │ │ │ ├── mavlink_msg_gopro_heartbeat.h │ │ │ ├── mavlink_msg_gopro_set_request.h │ │ │ ├── mavlink_msg_gopro_set_response.h │ │ │ ├── mavlink_msg_gps_accuracy.h │ │ │ ├── mavlink_msg_hwstatus.h │ │ │ ├── mavlink_msg_led_control.h │ │ │ ├── mavlink_msg_limits_status.h │ │ │ ├── mavlink_msg_mag_cal_progress.h │ │ │ ├── mavlink_msg_mag_cal_report.h │ │ │ ├── mavlink_msg_meminfo.h │ │ │ ├── mavlink_msg_mount_configure.h │ │ │ ├── mavlink_msg_mount_control.h │ │ │ ├── mavlink_msg_mount_status.h │ │ │ ├── mavlink_msg_pid_tuning.h │ │ │ ├── mavlink_msg_radio.h │ │ │ ├── mavlink_msg_rally_fetch_point.h │ │ │ ├── mavlink_msg_rally_point.h │ │ │ ├── mavlink_msg_rangefinder.h │ │ │ ├── mavlink_msg_remote_log_block_status.h │ │ │ ├── mavlink_msg_remote_log_data_block.h │ │ │ ├── mavlink_msg_sensor_offsets.h │ │ │ ├── mavlink_msg_set_mag_offsets.h │ │ │ ├── mavlink_msg_simstate.h │ │ │ ├── mavlink_msg_wind.h │ │ │ ├── testsuite.h │ │ │ └── version.h │ │ ├── checksum.h │ │ ├── common │ │ │ ├── common.h │ │ │ ├── mavlink.h │ │ │ ├── mavlink_msg_actuator_control_target.h │ │ │ ├── mavlink_msg_att_pos_mocap.h │ │ │ ├── mavlink_msg_attitude.h │ │ │ ├── mavlink_msg_attitude_quaternion.h │ │ │ ├── mavlink_msg_attitude_quaternion_cov.h │ │ │ ├── mavlink_msg_attitude_target.h │ │ │ ├── mavlink_msg_auth_key.h │ │ │ ├── mavlink_msg_autopilot_version.h │ │ │ ├── mavlink_msg_battery_status.h │ │ │ ├── mavlink_msg_camera_trigger.h │ │ │ ├── mavlink_msg_change_operator_control.h │ │ │ ├── mavlink_msg_change_operator_control_ack.h │ │ │ ├── mavlink_msg_command_ack.h │ │ │ ├── mavlink_msg_command_int.h │ │ │ ├── mavlink_msg_command_long.h │ │ │ ├── mavlink_msg_data_stream.h │ │ │ ├── mavlink_msg_data_transmission_handshake.h │ │ │ ├── mavlink_msg_debug.h │ │ │ ├── mavlink_msg_debug_vect.h │ │ │ ├── mavlink_msg_distance_sensor.h │ │ │ ├── mavlink_msg_encapsulated_data.h │ │ │ ├── mavlink_msg_file_transfer_protocol.h │ │ │ ├── mavlink_msg_global_position_int.h │ │ │ ├── mavlink_msg_global_position_int_cov.h │ │ │ ├── mavlink_msg_global_vision_position_estimate.h │ │ │ ├── mavlink_msg_gps2_raw.h │ │ │ ├── mavlink_msg_gps2_rtk.h │ │ │ ├── mavlink_msg_gps_global_origin.h │ │ │ ├── mavlink_msg_gps_inject_data.h │ │ │ ├── mavlink_msg_gps_raw_int.h │ │ │ ├── mavlink_msg_gps_rtk.h │ │ │ ├── mavlink_msg_gps_status.h │ │ │ ├── mavlink_msg_heartbeat.h │ │ │ ├── mavlink_msg_highres_imu.h │ │ │ ├── mavlink_msg_hil_controls.h │ │ │ ├── mavlink_msg_hil_gps.h │ │ │ ├── mavlink_msg_hil_optical_flow.h │ │ │ ├── mavlink_msg_hil_rc_inputs_raw.h │ │ │ ├── mavlink_msg_hil_sensor.h │ │ │ ├── mavlink_msg_hil_state.h │ │ │ ├── mavlink_msg_hil_state_quaternion.h │ │ │ ├── mavlink_msg_landing_target.h │ │ │ ├── mavlink_msg_local_position_ned.h │ │ │ ├── mavlink_msg_local_position_ned_cov.h │ │ │ ├── mavlink_msg_local_position_ned_system_global_offset.h │ │ │ ├── mavlink_msg_log_data.h │ │ │ ├── mavlink_msg_log_entry.h │ │ │ ├── mavlink_msg_log_erase.h │ │ │ ├── mavlink_msg_log_request_data.h │ │ │ ├── mavlink_msg_log_request_end.h │ │ │ ├── mavlink_msg_log_request_list.h │ │ │ ├── mavlink_msg_manual_control.h │ │ │ ├── mavlink_msg_manual_setpoint.h │ │ │ ├── mavlink_msg_memory_vect.h │ │ │ ├── mavlink_msg_mission_ack.h │ │ │ ├── mavlink_msg_mission_clear_all.h │ │ │ ├── mavlink_msg_mission_count.h │ │ │ ├── mavlink_msg_mission_current.h │ │ │ ├── mavlink_msg_mission_item.h │ │ │ ├── mavlink_msg_mission_item_int.h │ │ │ ├── mavlink_msg_mission_item_reached.h │ │ │ ├── mavlink_msg_mission_request.h │ │ │ ├── mavlink_msg_mission_request_list.h │ │ │ ├── mavlink_msg_mission_request_partial_list.h │ │ │ ├── mavlink_msg_mission_set_current.h │ │ │ ├── mavlink_msg_mission_write_partial_list.h │ │ │ ├── mavlink_msg_named_value_float.h │ │ │ ├── mavlink_msg_named_value_int.h │ │ │ ├── mavlink_msg_nav_controller_output.h │ │ │ ├── mavlink_msg_optical_flow.h │ │ │ ├── mavlink_msg_optical_flow_rad.h │ │ │ ├── mavlink_msg_param_map_rc.h │ │ │ ├── mavlink_msg_param_request_list.h │ │ │ ├── mavlink_msg_param_request_read.h │ │ │ ├── mavlink_msg_param_set.h │ │ │ ├── mavlink_msg_param_value.h │ │ │ ├── mavlink_msg_ping.h │ │ │ ├── mavlink_msg_position_target_global_int.h │ │ │ ├── mavlink_msg_position_target_local_ned.h │ │ │ ├── mavlink_msg_power_status.h │ │ │ ├── mavlink_msg_radio_status.h │ │ │ ├── mavlink_msg_raw_imu.h │ │ │ ├── mavlink_msg_raw_pressure.h │ │ │ ├── mavlink_msg_rc_channels.h │ │ │ ├── mavlink_msg_rc_channels_override.h │ │ │ ├── mavlink_msg_rc_channels_raw.h │ │ │ ├── mavlink_msg_rc_channels_scaled.h │ │ │ ├── mavlink_msg_request_data_stream.h │ │ │ ├── mavlink_msg_safety_allowed_area.h │ │ │ ├── mavlink_msg_safety_set_allowed_area.h │ │ │ ├── mavlink_msg_scaled_imu.h │ │ │ ├── mavlink_msg_scaled_imu2.h │ │ │ ├── mavlink_msg_scaled_imu3.h │ │ │ ├── mavlink_msg_scaled_pressure.h │ │ │ ├── mavlink_msg_scaled_pressure2.h │ │ │ ├── mavlink_msg_serial_control.h │ │ │ ├── mavlink_msg_servo_output_raw.h │ │ │ ├── mavlink_msg_set_actuator_control_target.h │ │ │ ├── mavlink_msg_set_attitude_target.h │ │ │ ├── mavlink_msg_set_gps_global_origin.h │ │ │ ├── mavlink_msg_set_mode.h │ │ │ ├── mavlink_msg_set_position_target_global_int.h │ │ │ ├── mavlink_msg_set_position_target_local_ned.h │ │ │ ├── mavlink_msg_sim_state.h │ │ │ ├── mavlink_msg_statustext.h │ │ │ ├── mavlink_msg_sys_status.h │ │ │ ├── mavlink_msg_system_time.h │ │ │ ├── mavlink_msg_terrain_check.h │ │ │ ├── mavlink_msg_terrain_data.h │ │ │ ├── mavlink_msg_terrain_report.h │ │ │ ├── mavlink_msg_terrain_request.h │ │ │ ├── mavlink_msg_timesync.h │ │ │ ├── mavlink_msg_v2_extension.h │ │ │ ├── mavlink_msg_vfr_hud.h │ │ │ ├── mavlink_msg_vicon_position_estimate.h │ │ │ ├── mavlink_msg_vision_position_estimate.h │ │ │ ├── mavlink_msg_vision_speed_estimate.h │ │ │ ├── testsuite.h │ │ │ └── version.h │ │ ├── mavlink_conversions.h │ │ ├── mavlink_helpers.h │ │ ├── mavlink_types.h │ │ └── protocol.h │ └── generate ├── mavpkt │ ├── Makefile │ └── mavpkt.cpp ├── old │ ├── app_streamer.py │ ├── logd.py │ ├── mavproxy_solo.py │ ├── pixrc.py │ ├── rssi_send.py │ ├── runMavproxy.sh │ ├── simple_stats.py │ ├── slip.py │ ├── stm32.py │ └── stm32_sim.py ├── pixrc │ ├── Makefile │ ├── RcCommander.cpp │ ├── RcCommander.h │ ├── pixrc.cpp │ ├── rc_ipc.c │ ├── rc_ipc.h │ ├── rc_pkt.h │ └── test_pixrc.cpp ├── proc_top │ ├── Makefile │ └── main.c ├── python │ ├── SoloLED.py │ ├── app_server.py │ ├── ath9k.py │ ├── attic │ │ └── checkPixBaud.py │ ├── gpio.py │ ├── led_control.py │ ├── led_nop.py │ ├── led_solo.py │ ├── lsproc.py │ ├── pixhawk.py │ ├── rc_lock.py │ ├── runStickCal.sh │ ├── slip.py │ ├── stick-cal.py │ ├── stm32_defs.py │ ├── usb_nop.py │ └── usb_solo.py ├── rssi │ ├── Makefile │ └── rssi_send.cpp ├── stm32 │ ├── .gitignore │ ├── AppConnected.h │ ├── ButtonEventHandler.cpp │ ├── ButtonEventHandler.h │ ├── ButtonFunctionCfg.cpp │ ├── ButtonFunctionCfg.h │ ├── CircularBuffer.cpp │ ├── CircularBuffer.h │ ├── CircularBufferTest.cpp │ ├── ConfigStickAxes.cpp │ ├── ConfigStickAxes.h │ ├── ConfigSweepTime.cpp │ ├── ConfigSweepTime.h │ ├── InputReport.cpp │ ├── InputReport.h │ ├── LockoutState.cpp │ ├── LockoutState.h │ ├── Makefile │ ├── PacketHandler.cpp │ ├── PacketHandler.h │ ├── PairReq.cpp │ ├── PairReq.h │ ├── PairRes.h │ ├── ParamStoredVals.h │ ├── RC.cpp │ ├── RC.h │ ├── SLIP.cpp │ ├── SLIP.h │ ├── SerialLog.cpp │ ├── SerialLog.h │ ├── SerialLogTest.cpp │ ├── SetShotInfo.cpp │ ├── SetShotInfo.h │ ├── SetTelemUnits.cpp │ ├── SetTelemUnits.h │ ├── SoloMessage.cpp │ ├── SoloMessage.h │ ├── SysInfo.cpp │ ├── SysInfo.h │ ├── TcpServer.cpp │ ├── TcpServer.h │ ├── Telem.cpp │ ├── Telem.h │ ├── Updater.h │ ├── app_connected_msg.py │ ├── btn_client.py │ ├── config_stick_axes.py │ ├── config_stick_axes_msg.py │ ├── config_sweep_time.py │ ├── config_sweep_time_msg.py │ ├── input_report_client.py │ ├── input_report_msg.py │ ├── lockout_msg.py │ ├── packetTypes.h │ ├── param_stored_vals_msg.py │ ├── set_telem_units.py │ ├── set_telem_units_msg.py │ ├── stm32.cpp │ └── updater_msg.py ├── telem │ ├── Makefile │ ├── telem_forward.cpp │ └── test_telem.cpp ├── telem_ctrl │ ├── Makefile │ ├── telem_ctrl.cpp │ ├── telem_dest.cpp │ └── telem_dest.h ├── telem_test │ ├── Makefile │ └── telem_test.cpp ├── thermal │ └── log_temp ├── tlog │ ├── Makefile │ └── tlog.cpp ├── unlock │ ├── Makefile │ └── unlock.cpp ├── util │ ├── ButtonEventMessage.cpp │ ├── ButtonEventMessage.h │ ├── Makefile │ ├── RcLock.cpp │ ├── RcLock.h │ ├── arp_table.c │ ├── arp_table.h │ ├── file_util.c │ ├── file_util.h │ ├── hostapd_ctrl.c │ ├── hostapd_ctrl.h │ ├── link_packet.h │ ├── main.c │ ├── mutex.c │ ├── mutex.h │ ├── net_stats.c │ ├── net_stats.h │ ├── net_wmm.h │ ├── proc_table.c │ ├── proc_table.h │ ├── syslog.c │ ├── syslog_test.c │ ├── syslog_test.h │ ├── util.c │ ├── util.h │ ├── util_test.c │ └── util_test.h ├── video │ ├── README │ ├── app │ │ ├── Makefile │ │ └── app_streamer.cpp │ ├── cleanLibs.sh │ ├── hdmi │ │ ├── Makefile │ │ └── hdmiout.c │ └── vid │ │ ├── 80211.cpp │ │ ├── 80211.h │ │ ├── Makefile │ │ └── vidlaunch.cpp └── wdog │ ├── Makefile │ └── wdog.c ├── gimbal ├── firmware_helper.py ├── firmware_loader.py ├── loadGimbal.py ├── setup.py ├── setup_comutation.py ├── setup_factory_pub.py ├── setup_mavlink.py ├── setup_param.py └── setup_validate.py ├── init ├── 3dr_rotate ├── clock_sync ├── golden_to_system.sh ├── pixhawk ├── shutdownArtoo.sh ├── startwd └── updateGimbal.sh ├── net ├── etc │ └── init.d │ │ ├── hostapd │ │ ├── netinit │ │ └── networking └── usr │ └── bin │ ├── .gitignore │ ├── clock.py │ ├── configfile.py │ ├── getmaclocal.py │ ├── hostapdconfig.py │ ├── ip.py │ ├── iw.py │ ├── rc_cli.py │ ├── rc_remap_sample.py │ ├── telem_ctrl.py │ └── wpa_supplicant.py ├── pair ├── hostapd_ctrl.py ├── ifconfig.py ├── ip_util.py ├── pair.py ├── pair_button.py ├── pair_confirm.py ├── pair_server.py ├── pair_solo.py ├── runlevel.py ├── udhcpc.py ├── wpa_cli.py ├── wpa_control.py ├── wpa_supplicant_init ├── wps_confirm.py └── wps_pair_msg.py ├── px_uploader ├── loadPixhawk.py └── px_uploader.py ├── tools ├── 3dcp ├── 3dsh ├── build │ ├── clang-format-run.py │ └── sololink_new ├── logdownload │ └── grabSoloLinkLogs.sh ├── scripts │ └── px_usb_switch.py ├── setregdomain │ └── setCountryCode.sh ├── updater │ ├── .gitignore │ ├── fetchLatest.sh │ ├── makeGolden.sh │ ├── unpair │ ├── updateFuncs │ ├── updateSoloAndArtoo.sh │ └── updateTest └── wifiTest │ ├── ArtooTest.sh │ └── SoloTest.sh └── wifi ├── Makefile ├── logRCUp.sh ├── survey_dump.c ├── survey_log └── wifistats.c /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AllowShortFunctionsOnASingleLine: false 5 | BreakBeforeBinaryOperators: true 6 | AlwaysBreakTemplateDeclarations: true 7 | ColumnLimit: 100 8 | Standard: Cpp11 9 | IndentWidth: 4 10 | UseTab: Never 11 | BreakBeforeBraces: Linux 12 | #AlignConsecutiveAssignments: true # only available as of clang-format 3.7 13 | BreakBeforeBinaryOperators: false 14 | PointerAlignment: Right 15 | # SpacesInAngles needed for nested templates (gcc 4.8.4 errors) 16 | SpacesInAngles: true 17 | --- 18 | # other lang configs here... 19 | ... 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # osx junk 2 | *.DS_Store 3 | 4 | # object files 5 | *.o 6 | *.pyc 7 | 8 | # pycharm files 9 | .idea 10 | 11 | # logs from sim 12 | *.tlog 13 | *.tlog.raw 14 | *.parm 15 | -------------------------------------------------------------------------------- /COPYRIGHT-3DR: -------------------------------------------------------------------------------- 1 | Copyright 2014-2017 3D Robotics 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use these files except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | ~~~~ 16 | 17 | Contributors prior to public release: 18 | 19 | * Eric Liao 20 | * John Finley 21 | * Allan Matthew 22 | * Will Silva 23 | * Liam Staskawicz 24 | * Angus Peart 25 | * Igor Napolskikh 26 | * Tim Ryan 27 | * Peter Barker 28 | * Robert Cottrell 29 | * Ramón Roche 30 | * Adam Setapen 31 | * Kevin Mehall 32 | * Jonathan Challinger 33 | * Nick Speal 34 | * Siddharth Bharat Purohit 35 | * Andrew Tridgell 36 | * Daniel Nugent 37 | * Chavi Weingarten 38 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | SUBDIRS = flightcode wifi 3 | SUBDIRS_BUILD = $(SUBDIRS:%=%_build) 4 | SUBDIRS_CLEAN = $(SUBDIRS:%=%_clean) 5 | 6 | # SUBDIRS2 should eventually be same as SUBDIRS when all are formatted 7 | 8 | SUBDIRS2 = flightcode 9 | SUBDIRS_FMT = $(SUBDIRS2:%=%_fmt) 10 | SUBDIRS_FMT_DIFF = $(SUBDIRS2:%=%_fmt-diff) 11 | 12 | all: $(SUBDIRS_BUILD) 13 | 14 | build: $(SUBDIRS_BUILD) 15 | $(SUBDIRS_BUILD): 16 | $(MAKE) -C $(@:%_build=%) 17 | 18 | clean: $(SUBDIRS_CLEAN) 19 | $(SUBDIRS_CLEAN): 20 | $(MAKE) -C $(@:%_clean=%) clean 21 | 22 | fmt: $(SUBDIRS_FMT) 23 | $(SUBDIRS_FMT): 24 | $(MAKE) -C $(@:%_fmt=%) fmt 25 | 26 | fmt-diff: $(SUBDIRS_FMT_DIFF) 27 | $(SUBDIRS_FMT_DIFF): 28 | $(MAKE) -C $(@:%_fmt-diff=%) fmt-diff 29 | 30 | .PHONY: $(SUBDIRS) $(SUBDIRS_BUILD) $(SUBDIRS_CLEAN) $(SUBDIRS_FMT) $(SUBDIRS_FMT_DIFF) 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WARNING - WORK IN PROGRESS 2 | 3 | ``` 4 | This code is known to be high risk , but also early-adopter friendly. 5 | 6 | We will remove this warning from the repository when it is no longer required. 7 | ``` 8 | 9 | 10 | SoloLink 11 | ======== 12 | 13 | Software for the SoloLink 14 | -------------------------------------------------------------------------------- /SOURCE: -------------------------------------------------------------------------------- 1 | This source code was released by 3DR in the file: sololink_2.2.4_ff71bb8f.tar.gz 2 | -------------------------------------------------------------------------------- /STM32Loader/reset_artoo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # -d 'N': delay 'N' seconds during reset 4 | # -n: don't kill stm32 process 5 | 6 | usage() { 7 | echo "usage: reset_artoo [-d N] [-n]" 8 | echo " -d N delay N seconds with reset asserted" 9 | echo " -n don't kill the stm32 process (debug usage)" 10 | } 11 | 12 | delay=0 13 | dokill=true 14 | until [ -z "${1}" ]; do 15 | case ${1} in 16 | -d) 17 | if [ -z "${2}" ]; then 18 | usage 19 | fi 20 | delay="${2}" 21 | shift 22 | ;; 23 | -n) 24 | dokill=false 25 | ;; 26 | esac 27 | shift 28 | done 29 | 30 | pin_boot=45 31 | pin_reset=46 32 | 33 | set_pin() { 34 | pushd /sys/class/gpio > /dev/null 35 | if [ ! -e gpio${1} ]; then 36 | echo "${1}" > /sys/class/gpio/export 37 | fi 38 | echo "out" > /sys/class/gpio/gpio${1}/direction 39 | echo "${2}" > /sys/class/gpio/gpio${1}/value 40 | popd > /dev/null 41 | } 42 | 43 | if ${dokill}; then 44 | # stop it 45 | init 2 46 | # wait for it to be truly gone 47 | until ! killall -q -CONT stm32; do 48 | true 49 | done 50 | fi 51 | 52 | # deassert boot 53 | set_pin ${pin_boot} 0 54 | 55 | # pulse reset 56 | set_pin ${pin_reset} 1 57 | sleep ${delay} 58 | set_pin ${pin_reset} 0 59 | 60 | if ${dokill}; then 61 | # restart everything 62 | init 3 63 | fi 64 | -------------------------------------------------------------------------------- /STM32Loader/stm32_check_cal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # stm32loader in /usr/bin is not on the default python path; make 4 | # sure we always find it no matter where this script is installed 5 | import sys 6 | sys.path.append("/usr/bin") 7 | import stm32loader 8 | 9 | stm32loader.QUIET = 0 10 | 11 | cmd = stm32loader.CommandInterface() 12 | cmd.open("/dev/ttymxc1", 115200) 13 | cmd.initChip() 14 | cmd.cmdGet() 15 | cmd.cmdGetID() 16 | 17 | status = 1 18 | 19 | msg = "cal is blank" 20 | 21 | try: 22 | data = cmd.readMemory(0x0803f800, 2048) 23 | for c in data: 24 | if c != 255: 25 | msg = "cal is not blank" 26 | status = 0 27 | break 28 | except: 29 | msg = "error reading cal (readout protect?)" 30 | pass 31 | 32 | cmd.releaseChip() 33 | 34 | print msg 35 | 36 | sys.exit(status) 37 | -------------------------------------------------------------------------------- /STM32Loader/stm32_readout_protect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # stm32loader in /usr/bin is not on the default python path; make 4 | # sure we always find it no matter where this script is installed 5 | import sys 6 | sys.path.append("/usr/bin") 7 | import stm32loader 8 | 9 | cmd = stm32loader.CommandInterface() 10 | cmd.open("/dev/ttymxc1", 115200) 11 | cmd.initChip() 12 | cmd.cmdGet() 13 | cmd.cmdGetID() 14 | cmd.cmdReadoutProtect() 15 | cmd.releaseChip() 16 | -------------------------------------------------------------------------------- /STM32Loader/stm32_reset.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # stm32loader in /usr/bin is not on the default python path; make 4 | # sure we always find it no matter where this script is installed 5 | import sys 6 | sys.path.append("/usr/bin") 7 | import stm32loader 8 | 9 | cmd = stm32loader.CommandInterface() 10 | cmd.open("/dev/ttymxc1", 115200) 11 | cmd.initChip() 12 | cmd.cmdGet() 13 | cmd.cmdGetID() 14 | cmd.releaseChip() 15 | -------------------------------------------------------------------------------- /STM32Loader/test_save_stick_cal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Purpose of this test 4 | # Enable readout protect and then attempt an artoo update. 5 | # Artoo parameters (i.e. stick cals) should not be wiped. 6 | # Test for IG-1435 7 | 8 | # Note that this test doesn't always work 9 | # because for some reason I need to run stm32_readout_protect.py a couple times for it to take effect, 10 | # but it should be kept around as inspiration for how to test this functionality manually. 11 | # Testing via a hard power cycle could be more representative than reboot anyway 12 | 13 | # Preconditions for this test: 14 | # Controller is on Solo v2.4.2-1, with Artoo 1.2.11. 15 | # A firmware file for Artoo 1.2.11 named 1.2.22 exists in /firmware/loaded 16 | # stm32_readout_protect.py and this file have been copied from the sololink repo (stm32loader folder) into artoo:/usr/bin 17 | 18 | init 2 # Stop the stm32 process 19 | sleep 5 20 | cp /firmware/loaded/artoo_1.2.12.bin /firmware/ 21 | python /usr/bin/stm32_readout_protect.py # Enable Readout Protect 22 | echo "Rebooting the controller. Once it comes up, check /log/3dr-solo.log for test results." 23 | sync 24 | reboot -------------------------------------------------------------------------------- /STM32Loader/updateArtoo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Comment out the RCTX line in /etc/inittab 4 | sed -i 's/^RCTX.*/#&/g' /etc/inittab 5 | 6 | #stop the stm32 process 7 | init q 8 | sleep 1 9 | 10 | # update artoo 11 | # we only erase the first 127 pages since the stm32 stores param data in its last page. 12 | # the stm32 we're currently using has 128 pages of 2k each - this will need to change if we 13 | # ever use different stm32 varieties. 14 | stm32loader.py -vw -s 127 -p /dev/ttymxc1 /home/root/artoo.bin 15 | 16 | # note - verification 17 | # you can read back the last page to verify that it wasn't overwritten in the update process: 18 | # 19 | # ./stm32loader.py -r -a 0x803f800 -l 2048 -p /dev/ttymxc1 readback.bin 20 | # hexdump readback.bin 21 | # 22 | # if it's not all 0xff's you're in good shape! 23 | 24 | #Uncomment the RCTX line 25 | sed -i 's/.\(RCTX*.\)/\1/g' /etc/inittab 26 | 27 | #start the stm32 process back up 28 | init q 29 | -------------------------------------------------------------------------------- /config/checknet: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Verify network device exists, and reboot if it does not 4 | 5 | # This is a workaround for the case where the PCIe phy does not initialize, 6 | # which happens a few percent of the time. The user-facing effect is that 7 | # startup takes about 20 seconds longer if the phy does not initialize. 8 | # 9 | # It would be better to do this from the initrd. 10 | # 11 | # It would be better still to fix the PCIe driver to reset and try again (or 12 | # something). Simple fixes (e.g. increasing the training time) did not work. 13 | # The imx6 PCIe driver in the 3.14.38 BSP is considerably different from the 14 | # one in the 3.10.17 BSP, so perhaps it will be fixed when we update. 15 | 16 | kmsg() { 17 | echo "$@" > /dev/kmsg 18 | } 19 | 20 | # wlan0 exists on both solo and controller 21 | # (although normally it is not used on controller) 22 | kmsg -n "Checking wlan0... " 23 | 24 | if [ ! -e /sys/class/net/wlan0 ]; then 25 | kmsg "NOT FOUND" 26 | # all logs except boot have been rotated at this point; 27 | # stop and rotate it keep them all in sync 28 | /etc/init.d/bootlogd stop 29 | shutdown -r now 30 | # don't let any more startup scripts start 31 | sleep 60 32 | else 33 | kmsg "OK" 34 | fi 35 | -------------------------------------------------------------------------------- /config/logrotate-sololink.conf.controller: -------------------------------------------------------------------------------- 1 | # see "man logrotate" for details 2 | # rotate logs, keeping 20 versions 3 | 4 | # specifying 'create' makes it so the log file is always there, even if 5 | # nothing writes to it on a particular run, so on the next rotation, the empty 6 | # file is rotated along with all the others, keeping the .N extensions in sync 7 | # (e.g. so all the .2 files are from the same run). 8 | 9 | # specifying 'missingok' is needed for the very first run when there are no 10 | # log files to rotate. 11 | 12 | create 13 | missingok 14 | rotate 20 15 | nodateext 16 | 17 | /log/3dr-top.log { } 18 | /log/3dr-solo.log { } 19 | /log/3dr-stm32.log { } 20 | /log/3dr-video.log { } 21 | /log/3dr-wifi.log { } 22 | /log/3dr-temp.log { } 23 | /log/pkt_delays.csv { } 24 | -------------------------------------------------------------------------------- /config/logrotate-sololink.conf.solo: -------------------------------------------------------------------------------- 1 | # see "man logrotate" for details 2 | # rotate logs, keeping 20 versions 3 | 4 | # specifying 'create' makes it so the log file is always there, even if 5 | # nothing writes to it on a particular run, so on the next rotation, the empty 6 | # file is rotated along with all the others, keeping the .N extensions in sync 7 | # (e.g. so all the .2 files are from the same run). 8 | 9 | # specifying 'missingok' is needed for the very first run when there are no 10 | # log files to rotate. 11 | 12 | create 13 | missingok 14 | rotate 20 15 | nodateext 16 | 17 | /log/3dr-top.log { } 18 | /log/3dr-solo.log { } 19 | /log/3dr-rc.log { } 20 | /log/3dr-telem.log { } 21 | /log/3dr-wifi.log { } 22 | /log/3dr-video.log { } 23 | /log/3dr-temp.log { } 24 | /log/shotlog.log { } 25 | /log/3dr-accessorykit.log { } 26 | -------------------------------------------------------------------------------- /config/max_dgram_qlen: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | echo "100" > /proc/sys/net/unix/max_dgram_qlen 3 | echo "max_dgram_qlen=`cat /proc/sys/net/unix/max_dgram_qlen`" 4 | -------------------------------------------------------------------------------- /config/sololink: -------------------------------------------------------------------------------- 1 | # This file goes in /etc/profile.d/ and is sourced by /etc/profile at boot time 2 | # Contents are created by sololink recipe, and should end up looking something 3 | # like this: 4 | # export SOLOLINK_CONFIG_DIR=/etc 5 | # export SOLOLINK_LOG_DIR=/log 6 | -------------------------------------------------------------------------------- /config/sololink_config_sample: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # run_cmd prints a command, then the command's output, then 'ok' or 'error', 4 | # depending on the command's exit status, then a blank line. 5 | # 6 | # All text after the command and before the 'ok' or 'error' is what the 7 | # command sends to stdout. 8 | run_cmd() { 9 | echo $1 10 | $1 11 | if [ $? -eq 0 ]; then echo "ok"; else echo "error"; fi 12 | echo 13 | } 14 | 15 | for SSH in "ssh root@10.1.1.1" "ssh root@10.1.1.10"; do 16 | 17 | run_cmd "$SSH sololink_config --get-version" 18 | run_cmd "$SSH sololink_config --get-version sololink" 19 | run_cmd "$SSH sololink_config --get-version artoo" 20 | run_cmd "$SSH sololink_config --get-version pixhawk" 21 | run_cmd "$SSH sololink_config --get-version golden" 22 | run_cmd "$SSH sololink_config --get-version all" 23 | run_cmd "$SSH sololink_config --get-wifi-ssid" 24 | run_cmd "$SSH sololink_config --get-wifi-password" 25 | run_cmd "$SSH sololink_config --get-image" 26 | run_cmd "$SSH sololink_config --get-pairing" 27 | 28 | done 29 | -------------------------------------------------------------------------------- /config/syslog.conf.busybox.controller: -------------------------------------------------------------------------------- 1 | # Configuration file for busybox's syslogd utility 2 | local0.info /log/3dr-stm32.log 3 | local1.info /log/3dr-solo.log 4 | local2.info /log/3dr-wifi.log 5 | local3.info /log/3dr-video.log 6 | 7 | local5.info /log/3dr-temp.log 8 | 9 | kern,user.* /log/kern.log 10 | -------------------------------------------------------------------------------- /config/syslog.conf.busybox.solo: -------------------------------------------------------------------------------- 1 | # Configuration file for busybox's syslogd utility 2 | local0.info /log/3dr-rc.log 3 | local1.info /log/3dr-solo.log 4 | local2.info /log/shotlog.log 5 | local3.info /log/3dr-wifi.log 6 | local4.info /log/3dr-telem.log 7 | local5.info /log/3dr-temp.log 8 | local6.info /log/3dr-video.log 9 | local7.info /log/3dr-accessorykit.log 10 | 11 | kern,user.* /log/kern.log 12 | -------------------------------------------------------------------------------- /config/test_3dr_README: -------------------------------------------------------------------------------- 1 | The directories test_3dr_controller and test_3dr_solo are used by the test 2 | script sololink_config_test. 3 | -------------------------------------------------------------------------------- /config/test_3dr_controller/STM_VERSION: -------------------------------------------------------------------------------- 1 | 0.6.9 2 | -------------------------------------------------------------------------------- /config/test_3dr_controller/VERSION: -------------------------------------------------------------------------------- 1 | 0.6.5 2 | -------------------------------------------------------------------------------- /config/test_3dr_controller/etc/hostapd.conf.md5: -------------------------------------------------------------------------------- 1 | a46c206ffafef83c91cebf497ea785b5 ./test_3dr_controller/etc/hostapd.conf 2 | -------------------------------------------------------------------------------- /config/test_3dr_solo/PIX_VERSION: -------------------------------------------------------------------------------- 1 | 0.0.28 2 | -------------------------------------------------------------------------------- /config/test_3dr_solo/VERSION: -------------------------------------------------------------------------------- 1 | 0.6.5 2 | -------------------------------------------------------------------------------- /config/test_3dr_solo/etc/wpa_supplicant.conf: -------------------------------------------------------------------------------- 1 | ctrl_interface=/var/run/wpa_supplicant 2 | ctrl_interface_group=0 3 | update_config=1 4 | device_name=Solo 5 | manufacturer=3D Robotics 6 | model_name=Solo 7 | -------------------------------------------------------------------------------- /config/test_3dr_solo/etc/wpa_supplicant.conf.md5: -------------------------------------------------------------------------------- 1 | 132d9621948cfb385c5975b51dec4758 ./test_3dr_solo/etc/wpa_supplicant.conf 2 | -------------------------------------------------------------------------------- /config/test_3dr_solo/mnt/rootfs.ro/etc/wpa_supplicant.orig: -------------------------------------------------------------------------------- 1 | ctrl_interface=/var/run/wpa_supplicant 2 | ctrl_interface_group=0 3 | update_config=1 4 | device_name=Solo 5 | manufacturer=3D Robotics 6 | model_name=Solo 7 | -------------------------------------------------------------------------------- /flightcode/Makefile: -------------------------------------------------------------------------------- 1 | 2 | SUBDIRS = 3 | SUBDIRS += arp_table 4 | SUBDIRS += dflog 5 | SUBDIRS += dataflash_logger 6 | SUBDIRS += hostapd_ctrl 7 | SUBDIRS += pixrc 8 | SUBDIRS += proc_top 9 | SUBDIRS += rssi 10 | SUBDIRS += stm32 11 | SUBDIRS += telem 12 | SUBDIRS += telem_ctrl 13 | SUBDIRS += tlog 14 | SUBDIRS += video/vid 15 | SUBDIRS += video/app 16 | SUBDIRS += video/hdmi 17 | SUBDIRS += unlock 18 | SUBDIRS += wdog 19 | 20 | SUBDIRS_BUILD = $(SUBDIRS:%=%_build) 21 | SUBDIRS_CLEAN = $(SUBDIRS:%=%_clean) 22 | 23 | # SUBDIRS2 is SUBDIRS, plus directories that can be formatted but not built 24 | SUBDIRS2 = $(SUBDIRS) 25 | SUBDIRS2 += ini 26 | SUBDIRS2 += ini/cpp 27 | SUBDIRS2 += log 28 | SUBDIRS2 += util 29 | 30 | SUBDIRS_FMT = $(SUBDIRS2:%=%_fmt) 31 | SUBDIRS_FMT_DIFF = $(SUBDIRS2:%=%_fmt-diff) 32 | 33 | all: $(SUBDIRS_BUILD) 34 | 35 | build: $(SUBDIRS_BUILD) 36 | $(SUBDIRS_BUILD): 37 | $(MAKE) -C $(@:%_build=%) 38 | 39 | clean: $(SUBDIRS_CLEAN) 40 | $(SUBDIRS_CLEAN): 41 | $(MAKE) -C $(@:%_clean=%) clean 42 | 43 | fmt: $(SUBDIRS_FMT) 44 | $(SUBDIRS_FMT): 45 | $(MAKE) -C $(@:%_fmt=%) fmt 46 | 47 | fmt-diff: $(SUBDIRS_FMT_DIFF) 48 | $(SUBDIRS_FMT_DIFF): 49 | $(MAKE) -C $(@:%_fmt-diff=%) fmt-diff 50 | 51 | .PHONY: $(SUBDIRS) $(SUBDIRS_BUILD) $(SUBDIRS_CLEAN) $(SUBDIRS_FMT) $(SUBDIRS_FMT_DIFF) 52 | -------------------------------------------------------------------------------- /flightcode/arp_table/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util 13 | 14 | INCS = -I../util 15 | 16 | CFLAGS += -Wall $(INCS) 17 | 18 | SRCS_C = main.c arp_table.c util.c 19 | 20 | OBJS = $(SRCS_C:.c=.o) 21 | 22 | MAIN = arp_table 23 | 24 | all: $(MAIN) 25 | 26 | $(MAIN): $(OBJS) 27 | $(LINK.c) -o $(MAIN) $(OBJS) $(LIBS) 28 | 29 | clean: 30 | $(RM) *.o *~ $(MAIN) 31 | 32 | BASE := ../.. 33 | 34 | fmt: 35 | @python $(BASE)/tools/build/clang-format-run.py --apply 36 | 37 | fmt-diff: 38 | @python $(BASE)/tools/build/clang-format-run.py 39 | 40 | .PHONY: all clean fmt fmt-diff 41 | -------------------------------------------------------------------------------- /flightcode/arp_table/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "arp_table.h" 7 | 8 | #define MAX_ARP_ENTRIES 10 9 | arp_entry_t arp_table[MAX_ARP_ENTRIES]; 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | int arp_entries; 14 | int i; 15 | 16 | arp_entries = MAX_ARP_ENTRIES; 17 | if (arp_table_get(arp_table, &arp_entries) != 0) { 18 | printf("ERROR reading arp table\n"); 19 | exit(1); 20 | } 21 | 22 | for (i = 0; i < arp_entries; i++) { 23 | struct in_addr in; 24 | in.s_addr = arp_table[i].ip; 25 | uint8_t *mac = arp_table[i].mac; 26 | printf("%-15s 0x%x 0x%x %02x:%02x:%02x:%02x:%02x:%02x %s\n", inet_ntoa(in), 27 | arp_table[i].hw_type, arp_table[i].flags, mac[0], mac[1], mac[2], mac[3], mac[4], 28 | mac[5], arp_table[i].dev); 29 | } 30 | 31 | exit(0); 32 | 33 | } /* main */ 34 | -------------------------------------------------------------------------------- /flightcode/baudcheck/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util 13 | 14 | INCS = -I../util 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) 18 | 19 | LIBS += -lpthread 20 | 21 | SRCS_CPP = baudcheck.cpp 22 | SRCS_C += util.c 23 | 24 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 25 | 26 | MAIN = baudcheck 27 | 28 | all: $(MAIN) 29 | 30 | $(MAIN): $(OBJS) 31 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 32 | 33 | clean: 34 | $(RM) *.o *~ $(MAIN) 35 | $(RM) ../util/*.o 36 | 37 | .PHONY: clean 38 | -------------------------------------------------------------------------------- /flightcode/command/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | CFLAGS += -Wall -g 13 | CXXFLAGS += -Wall -g 14 | 15 | LIBS = -lpthread 16 | 17 | SRCS_CPP = Commander.cpp 18 | #SRCS_CPP += ../ini/cpp/INIReader.cpp ../log/Log.cpp 19 | #SRCS_C = ../ini/ini.c 20 | 21 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 22 | 23 | MAIN = Commander 24 | 25 | all: $(MAIN) 26 | 27 | Commander.o: Commander.cpp Commander.h 28 | 29 | $(MAIN): $(OBJS) 30 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 31 | 32 | clean: 33 | $(RM) *.o *~ $(MAIN) 34 | #$(RM) ../ini/*.o 35 | #$(RM) ../ini/cpp/*.o 36 | #$(RM) ../log/*.o 37 | 38 | .PHONY: clean 39 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util ../ini ../ini/cpp 13 | 14 | INCS = -I../util -I../ini -I../ini/cpp 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) -std=c++11 18 | 19 | SRCS_CPP = dataflash_logger.cpp 20 | SRCS_CPP += common_tool.cpp 21 | SRCS_CPP += format_reader.cpp 22 | SRCS_CPP += telem_forwarder_client.cpp 23 | SRCS_CPP += mavlink_reader.cpp 24 | SRCS_CPP += analyzer_util.cpp 25 | SRCS_CPP += dataflash_logger_program.cpp 26 | SRCS_CPP += INIReader.cpp 27 | SRCS_CPP += mavlink_message_handler.cpp 28 | SRCS_CPP += mavlink_writer.cpp 29 | SRCS_CPP += telem_client.cpp 30 | SRCS_CPP += telem_serial.cpp 31 | SRCS_CPP += la-log.cpp 32 | SRCS_CPP += heart.cpp 33 | SRCS_C = util.c ini.c 34 | 35 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 36 | LIBS=-pthread 37 | 38 | MAIN = dataflash_logger # actually, the main is in mavlink_reader... 39 | 40 | all: $(MAIN) 41 | 42 | $(MAIN): $(OBJS) 43 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 44 | 45 | clean: 46 | $(RM) *.o *~ $(MAIN) 47 | 48 | BASE := ../.. 49 | 50 | fmt: 51 | @python $(BASE)/tools/build/clang-format-run.py --apply 52 | 53 | fmt-diff: 54 | @python $(BASE)/tools/build/clang-format-run.py 55 | 56 | .PHONY: clean 57 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/analyzer_util.cpp: -------------------------------------------------------------------------------- 1 | #include "analyzer_util.h" 2 | #include 3 | 4 | #include 5 | 6 | void format_timestamp(char *buf, const uint8_t buflen, const uint64_t T) 7 | { 8 | struct tm *tmp; 9 | time_t t = T / 1000000; 10 | tmp = localtime(&t); 11 | ::strftime(buf, buflen, "%Y%m%d%H%M%S", tmp); 12 | } 13 | 14 | uint64_t now() 15 | { 16 | struct timeval tv; 17 | gettimeofday(&tv, NULL); 18 | return tv.tv_sec * (uint64_t)1000000 + tv.tv_usec; 19 | } 20 | 21 | double vec_len(double vec[3]) 22 | { 23 | return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]); 24 | } 25 | 26 | double earthradius() // in metres 27 | { 28 | return 6371000.0f; 29 | } 30 | 31 | double wrap_valid_longitude(const double longitude) 32 | { 33 | if (longitude < 180.0f) { 34 | return longitude; 35 | } 36 | 37 | return 180 - (longitude - 180); 38 | // return (((longitude + 180.0) % 360.0) -180.0); 39 | } 40 | 41 | // http://www.movable-type.co.uk/scripts/latlong.html 42 | void gps_newpos(const double orig_lat, const double orig_lon, const double bearing, 43 | const double distance, double &dest_lat, double &dest_lon) 44 | { 45 | double origin_lat_rad = deg_to_rad(orig_lat); 46 | double origin_lon_rad = deg_to_rad(orig_lon); 47 | double bearing_rad = deg_to_rad(bearing); 48 | 49 | double dr = distance / earthradius(); 50 | 51 | dest_lat = 52 | asin(sin(origin_lat_rad) * cos(dr) + cos(origin_lat_rad) * sin(dr) * cos(bearing_rad)); 53 | dest_lon = origin_lon_rad + atan2(sin(bearing_rad) * sin(dr) * cos(origin_lat_rad), 54 | cos(dr) - sin(origin_lat_rad) * sin(origin_lat_rad)); 55 | dest_lat = rad_to_deg(dest_lat); 56 | dest_lon = wrap_valid_longitude(rad_to_deg(dest_lon)); 57 | } 58 | 59 | // origin_lat in degrees 60 | // origin_lon in degrees 61 | // bearing in degrees 62 | // distance in metres 63 | void gps_offset(double orig_lat, double orig_lon, double east, double north, double &dest_lat, 64 | double &dest_lon) 65 | { 66 | double bearing = rad_to_deg(atan2(east, north)); 67 | double distance = sqrt(east * east + north * north); 68 | gps_newpos(orig_lat, orig_lon, bearing, distance, dest_lat, dest_lon); 69 | } 70 | 71 | double altitude_from_pressure_delta(double gnd_abs_press, double gnd_temp, double press_abs, 72 | double temp UNUSED) 73 | { 74 | double scaling = press_abs / gnd_abs_press; 75 | return 153.8462 * (gnd_temp + 273.15) * (1.0 - exp(0.190259 * log(scaling))); 76 | } 77 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/analyzer_util.h: -------------------------------------------------------------------------------- 1 | #ifndef _ANALYZER_UTIL 2 | #define _ANALYZER_UTIL 3 | 4 | #include 5 | #include 6 | 7 | // from: http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf 8 | #include 9 | 10 | double earthradius(); 11 | 12 | double wrap_valid_longitude(const double longitude); 13 | 14 | // http://www.movable-type.co.uk/scripts/latlong.html 15 | void gps_newpos(const double orig_lat, const double orig_lon, const double bearing, 16 | const double distance, double &dest_lat, double &dest_lon); 17 | 18 | // origin_lat in degrees 19 | // origin_lon in degrees 20 | // bearing in degrees 21 | // distance in metres 22 | void gps_offset(double orig_lat, double orig_lon, double east, double north, double &dest_lat, 23 | double &dest_lon); 24 | 25 | double altitude_from_pressure_delta(double gnd_abs_press, double gnd_temp, double press_abs, 26 | double temp); 27 | 28 | template < typename... Args > 29 | std::string string_format(const char *format, const Args... args) 30 | { 31 | 32 | int32_t size = snprintf(nullptr, 0, format, args...); 33 | if (size < 0) { 34 | ::fprintf(stderr, "snprintf error (%d): %s\n", size, strerror(errno)); 35 | abort(); 36 | } 37 | size += 1; // Extra space for '\0' 38 | std::unique_ptr< char[] > buf(new char[size]); 39 | snprintf(buf.get(), size, format, args...); 40 | return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside 41 | } 42 | 43 | template < typename... Args > 44 | std::string string_format(const std::string format, const Args... args) 45 | { 46 | return string_format(format.c_str(), args...); 47 | } 48 | 49 | #ifndef streq 50 | #define streq(x, y) (!strcmp(x, y)) 51 | #endif 52 | 53 | // inline float deg_to_rad(const float deg) { 54 | // return deg/M_PI * 180; 55 | // } 56 | 57 | // inline float rad_to_deg(const float rad) { 58 | // return rad*180/M_PI; 59 | // } 60 | 61 | #define deg_to_rad(x) ((x)*M_PI / 180.0f) 62 | #define rad_to_deg(x) ((x)*180.0f / M_PI) 63 | 64 | #define is_zero(x) (x < 0.00001) 65 | #define is_equal(x, y) (is_zero(fabs((x) - (y)))) 66 | 67 | void format_timestamp(char *buf, uint8_t buflen, uint64_t T); 68 | 69 | uint64_t now(); 70 | 71 | double vec_len(double vec[3]); 72 | 73 | #define UNUSED __attribute__((unused)) 74 | 75 | #endif // _ANALYZER_UTIL 76 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/common_tool.h: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "analyzer_util.h" 3 | #include "INIReader.h" 4 | 5 | #include "format_reader.h" 6 | 7 | class Common_Tool 8 | { 9 | public: 10 | Common_Tool() : config_filename(default_config_filename) 11 | { 12 | } 13 | 14 | void sighup_handler(int signal); 15 | 16 | void parse_fd(Format_Reader *reader, int fd); 17 | 18 | protected: 19 | class INIReader *config() 20 | { 21 | return _config; 22 | }; 23 | void init_config(); 24 | const char *default_config_filename = "/etc/sololink.conf"; 25 | const char *config_filename; 26 | 27 | virtual void sighup_received_tophalf(); 28 | 29 | bool _sighup_received = false; // FIXME: scope 30 | 31 | virtual uint32_t select_timeout_us(); 32 | void select_loop(); 33 | 34 | virtual void pack_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, 35 | uint8_t &nfds); 36 | virtual void handle_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, 37 | uint8_t &nfds); 38 | virtual void do_idle_callbacks(); 39 | 40 | private: 41 | void check_fds_are_empty_after_select(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, 42 | uint8_t nfds); 43 | class INIReader *_config = NULL; 44 | }; 45 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/dataflash_logger_program.h: -------------------------------------------------------------------------------- 1 | #include "common_tool.h" 2 | 3 | #include "mavlink_reader.h" 4 | #include "mavlink_writer.h" 5 | #include "telem_client.h" 6 | 7 | class DataFlash_Logger_Program : public Common_Tool 8 | { 9 | public: 10 | DataFlash_Logger_Program() : Common_Tool() 11 | { 12 | } 13 | 14 | void run(); 15 | 16 | void parse_arguments(int argc, char *argv[]); 17 | const char *program_name(); 18 | 19 | void pack_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, 20 | uint8_t &nfds) override; 21 | void handle_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, 22 | uint8_t &nfds) override; 23 | 24 | private: 25 | void usage(); 26 | void sighup_received_tophalf() override; 27 | void do_idle_callbacks() override; 28 | uint32_t select_timeout_us() override; 29 | 30 | void do_writer_sends(); 31 | 32 | MAVLink_Reader *reader; 33 | MAVLink_Writer *_writer; 34 | 35 | long _argc = 0; 36 | char **_argv = NULL; 37 | 38 | uint8_t _client_recv_buf[512] = {}; // FIXME constant was TELEM_PKT_MAX 39 | 40 | static const uint32_t _client_buflen = 65536; // FIXME constant 41 | uint32_t _client_buflen_start = 0; 42 | uint32_t _client_buflen_stop = 0; 43 | 44 | Telem_Client *client = NULL; 45 | bool debug_mode = false; 46 | bool serial_port = false; 47 | // uint8_t _writer_buf[_writer_buflen] = { }; 48 | uint32_t canary = 9876543; 49 | }; 50 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/dataflash_message_handler.cpp: -------------------------------------------------------------------------------- 1 | #include "dataflash_message_handler.h" 2 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/dataflash_message_handler.h: -------------------------------------------------------------------------------- 1 | #ifndef DATAFLASH_MESSAGE_HANDLER_H 2 | #define DATAFLASH_MESSAGE_HANDLER_H 3 | 4 | #include 5 | 6 | /* 7 | * dataflash_message_handler 8 | * 9 | * A base class for objects which process dataflash messages and 10 | * possibly send responses 11 | * 12 | */ 13 | 14 | #include 15 | 16 | #include "INIReader.h" 17 | 18 | #include "message_handler.h" 19 | 20 | class DataFlash_Message_Handler : public Message_Handler 21 | { 22 | public: 23 | virtual void handle_format_message_received(const char *name, const struct log_Format &format, 24 | const char *msg) = 0; 25 | virtual void handle_message_received(const struct log_Format &format, const uint8_t *msg) = 0; 26 | 27 | protected: 28 | private: 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/format_reader.cpp: -------------------------------------------------------------------------------- 1 | #include "format_reader.h" 2 | 3 | #include "la-log.h" 4 | 5 | void Format_Reader::do_idle_callbacks() 6 | { 7 | uint64_t now_us = clock_gettime_us(CLOCK_MONOTONIC); 8 | if (next_100hz_time <= now_us) { 9 | for (int i = 0; i < next_message_handler; i++) { 10 | message_handler[i]->idle_100Hz(); 11 | } 12 | next_100hz_time += 10000; 13 | } 14 | if (next_10hz_time <= now_us) { 15 | for (int i = 0; i < next_message_handler; i++) { 16 | message_handler[i]->idle_10Hz(); 17 | } 18 | next_10hz_time += 100000; 19 | } 20 | if (next_1hz_time <= now_us) { 21 | for (int i = 0; i < next_message_handler; i++) { 22 | message_handler[i]->idle_1Hz(); 23 | } 24 | next_1hz_time += 1000000; 25 | } 26 | if (next_tenthhz_time <= now_us) { 27 | for (int i = 0; i < next_message_handler; i++) { 28 | message_handler[i]->idle_tenthHz(); 29 | } 30 | next_tenthhz_time += 10000000; 31 | } 32 | } 33 | 34 | bool Format_Reader::add_message_handler(Message_Handler *handler, const char *handler_name) 35 | { 36 | if (MAX_MESSAGE_HANDLERS - next_message_handler < 2) { 37 | la_log(LOG_INFO, "Insufficient message handler slots (MAX=%d) (next=%d)?!", 38 | MAX_MESSAGE_HANDLERS, next_message_handler); 39 | return false; 40 | } 41 | 42 | if (!handler->configure(_config)) { 43 | la_log(LOG_INFO, "Failed to configure (%s)", handler_name); 44 | return false; 45 | } 46 | 47 | message_handler[next_message_handler++] = handler; 48 | return true; 49 | } 50 | 51 | void Format_Reader::clear_message_handlers() 52 | { 53 | next_message_handler = 0; 54 | } 55 | 56 | void Format_Reader::sighup_handler() 57 | { 58 | for (int i = 0; i < next_message_handler; i++) { 59 | message_handler[i]->sighup_received(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/format_reader.h: -------------------------------------------------------------------------------- 1 | #ifndef FORMAT_READER_H 2 | #define FORMAT_READER_H 3 | 4 | #include "INIReader.h" 5 | #include "util.h" 6 | 7 | #include "message_handler.h" 8 | 9 | class Format_Reader 10 | { 11 | public: 12 | Format_Reader(INIReader *config) : _config(config) 13 | { 14 | uint64_t now_us = clock_gettime_us(CLOCK_MONOTONIC); 15 | next_tenthhz_time = now_us; 16 | next_1hz_time = now_us; 17 | next_10hz_time = now_us; 18 | next_100hz_time = now_us; 19 | }; 20 | 21 | void do_idle_callbacks(); 22 | 23 | virtual bool add_message_handler(Message_Handler *handler, const char *handler_name); 24 | virtual void clear_message_handlers(); 25 | 26 | virtual void sighup_handler(); 27 | 28 | virtual uint32_t feed(const uint8_t *buf, const uint32_t len) = 0; 29 | 30 | virtual void end_of_log(){}; 31 | 32 | protected: 33 | INIReader *_config; 34 | 35 | // FIXME: Scope 36 | #define MAX_MESSAGE_HANDLERS 10 37 | uint8_t next_message_handler = 0; 38 | Message_Handler *message_handler[MAX_MESSAGE_HANDLERS]; 39 | 40 | private: 41 | bool sighup_received = false; 42 | 43 | uint64_t next_tenthhz_time; 44 | uint64_t next_1hz_time; 45 | uint64_t next_10hz_time; 46 | uint64_t next_100hz_time; 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/heart.cpp: -------------------------------------------------------------------------------- 1 | #include "heart.h" 2 | 3 | #include "util.h" 4 | #include "la-log.h" 5 | 6 | void Heart::idle_10Hz() 7 | { 8 | uint64_t now_us = clock_gettime_us(CLOCK_MONOTONIC); 9 | if (last_heartbeat_time + heartbeat_interval < now_us) { 10 | last_heartbeat_time = now_us; 11 | beat(); 12 | } 13 | } 14 | 15 | bool Heart::configure(INIReader *config) 16 | { 17 | if (!MAVLink_Message_Handler::configure(config)) { 18 | return false; 19 | } 20 | return true; 21 | } 22 | 23 | void Heart::beat() 24 | { 25 | mavlink_message_t msg; 26 | 27 | uint8_t type = MAV_TYPE_GCS; 28 | uint8_t autopilot = MAV_AUTOPILOT_INVALID; 29 | uint8_t base_mode = 0; 30 | uint32_t custom_mode = 0; 31 | uint8_t system_status = 0; 32 | 33 | la_log(LOG_DEBUG, "mh-h: sending heartbeat"); 34 | 35 | mavlink_msg_heartbeat_pack(system_id, component_id, &msg, type, autopilot, base_mode, 36 | custom_mode, system_status); 37 | 38 | _mavlink_writer->send_message(msg); 39 | } 40 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/heart.h: -------------------------------------------------------------------------------- 1 | #ifndef HEART_H 2 | #define HEART_H 3 | 4 | /* 5 | * heart 6 | * 7 | * Periodically send mavlink heartbeats to our upstream connection 8 | * 9 | */ 10 | 11 | #include "mavlink_message_handler.h" 12 | #include "mavlink_writer.h" 13 | 14 | class Heart : public MAVLink_Message_Handler 15 | { 16 | 17 | public: 18 | Heart(MAVLink_Writer *mavlink_writer) 19 | : MAVLink_Message_Handler(), _mavlink_writer(mavlink_writer), last_heartbeat_time(0), 20 | heartbeat_interval(5000000) // microseconds 21 | { 22 | } 23 | 24 | void idle_10Hz(); 25 | bool configure(INIReader *config); 26 | 27 | private: 28 | MAVLink_Writer *_mavlink_writer = NULL; 29 | uint64_t last_heartbeat_time; 30 | const uint32_t heartbeat_interval; 31 | void beat(); 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/la-log.cpp: -------------------------------------------------------------------------------- 1 | #include "la-log.h" 2 | 3 | // Caution: the functions exposed in here are called by different 4 | // threads in the same process. 5 | 6 | LALog lalog; 7 | 8 | // globa functions for convenience 9 | void la_log_syslog_open() 10 | { 11 | lalog.syslog_open(); 12 | } 13 | 14 | void la_log_unsuppress() 15 | { 16 | lalog.unsupress(); 17 | } 18 | 19 | void la_log(int priority, const char *format, ...) 20 | { 21 | va_list ap; 22 | va_start(ap, format); 23 | lalog.log_ap(priority, format, ap); 24 | va_end(ap); 25 | } 26 | 27 | void LALog::syslog_open() 28 | { 29 | openlog("dl", LOG_NDELAY, LOG_LOCAL1); 30 | 31 | use_syslog = true; 32 | } 33 | 34 | void LALog::log(const int priority, const char *format, ...) 35 | { 36 | va_list ap; 37 | va_start(ap, format); 38 | log_ap(priority, format, ap); 39 | va_end(ap); 40 | } 41 | 42 | bool LALog::should_suppress() 43 | { 44 | return _message_count_this_time_period >= _max_messages_per_time_period; 45 | } 46 | 47 | void LALog::unsupress() 48 | { 49 | _suppressing = false; 50 | _message_count_this_time_period = 0; 51 | _time_period_start = time(NULL); 52 | if (_suppressed_message_count) { 53 | // hmmm. recursion. hmmm. 54 | log(LOG_ERR, "%d messages supressed", _suppressed_message_count); 55 | _message_count_this_time_period--; // *cough* let one 56 | // *message through 57 | // *apart from us.... 58 | _suppressed_message_count = 0; 59 | } 60 | } 61 | void LALog::log_ap(int priority, const char *format, va_list ap) 62 | { 63 | if (time(NULL) - _time_period_start > _time_period) { 64 | unsupress(); 65 | } 66 | if (should_suppress()) { 67 | _suppressing = true; 68 | } 69 | if (suppressing()) { 70 | _suppressed_message_count++; 71 | return; 72 | } 73 | 74 | _message_count_this_time_period++; 75 | 76 | if (use_syslog) { 77 | vsyslog(priority, format, ap); 78 | } else { 79 | vfprintf(stderr, format, ap); 80 | fprintf(stderr, "%s", "\n"); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/la-log.h: -------------------------------------------------------------------------------- 1 | #ifndef _LA_LOG_H 2 | #define _LA_LOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void la_log_syslog_open(); 11 | void la_log(int priority, const char *format, ...); 12 | void la_log_unsuppress(); 13 | 14 | class LALog 15 | { 16 | public: 17 | LALog() : _time_period_start(time(NULL)) 18 | { 19 | } 20 | void syslog_open(); 21 | 22 | void log(int priority, const char *format, ...); 23 | void log_ap(int priority, const char *format, va_list ap); 24 | 25 | void unsupress(); 26 | bool should_suppress(); 27 | bool suppressing() 28 | { 29 | return _suppressing; 30 | } 31 | 32 | private: 33 | // really rough rate limiting for log messages. We could keep a 34 | // hash here of formats and selectively supress based on format. 35 | bool _suppressing = false; 36 | const uint8_t _time_period = 5; // seconds 37 | const uint8_t _max_messages_per_time_period = 10; 38 | uint32_t _suppressed_message_count = 0; 39 | uint8_t _message_count_this_time_period = 0; 40 | time_t _time_period_start; 41 | 42 | bool use_syslog = false; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/mavlink_reader.h: -------------------------------------------------------------------------------- 1 | #ifndef MAVLINK_READER_H 2 | #define MAVLINK_READER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "INIReader.h" 8 | #include "util.h" 9 | 10 | #include "mavlink_message_handler.h" 11 | 12 | #include "format_reader.h" 13 | 14 | /* A mavlink packet should be limited to 6+255+2 = 263 bytes 15 | 6 byte header, 255 max bytes in payload, 2 byte crc */ 16 | #define TELEM_PKT_MAX 512 17 | 18 | class MAVLink_Reader : public Format_Reader 19 | { 20 | public: 21 | MAVLink_Reader(INIReader *config) 22 | : Format_Reader(config), err_skipped(0), err_time_us(0), /* last time we logged */ 23 | err_interval_us(1000000), /* once per second max */ 24 | _is_tlog(false) 25 | { 26 | } 27 | 28 | uint32_t feed(const uint8_t *buf, const uint32_t len) override; 29 | 30 | void set_is_tlog(bool value) 31 | { 32 | _is_tlog = value; 33 | } 34 | bool is_tlog() 35 | { 36 | return _is_tlog; 37 | } 38 | 39 | protected: 40 | void end_of_log() override; 41 | 42 | private: 43 | int can_log_error(); 44 | 45 | void handle_message_received(uint64_t timestamp, mavlink_message_t msg); 46 | 47 | uint16_t err_skipped; 48 | uint64_t err_time_us; 49 | uint64_t err_interval_us; 50 | 51 | uint32_t packet_count = 0; 52 | uint8_t timestamp_offset = 0; 53 | bool done_timestamp = false; 54 | uint64_t timestamp = 0; 55 | mavlink_message_t mav_msg; 56 | mavlink_status_t mav_status; 57 | 58 | bool _is_tlog; 59 | }; 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/mavlink_writer.cpp: -------------------------------------------------------------------------------- 1 | #include "mavlink_writer.h" 2 | 3 | #include 4 | 5 | void MAVLink_Writer::add_client(Telem_Client *client) 6 | { 7 | clients.push_back(client); 8 | } 9 | 10 | void MAVLink_Writer::send_message(const mavlink_message_t &msg) 11 | { 12 | // std::for_each(clients.begin(), clients.end(), send_message(msg)); 13 | std::for_each(clients.begin(), clients.end(), [msg](Telem_Client *c) { c->send_message(msg); }); 14 | // for (std::vector::iterator it = clients.begin(); 15 | // it != clients.end(); 16 | // it++) { 17 | // (*it)->send_message(msg); 18 | // } 19 | } 20 | 21 | bool MAVLink_Writer::any_data_to_send() 22 | { 23 | for (std::vector< Telem_Client * >::iterator it = clients.begin(); it != clients.end(); it++) { 24 | if ((*it)->any_data_to_send()) { 25 | return true; 26 | } 27 | } 28 | return false; 29 | } 30 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/mavlink_writer.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAVLINK_WRITER_H 2 | #define _MAVLINK_WRITER_H 3 | 4 | #include 5 | 6 | #include "../mavlink/c_library/ardupilotmega/mavlink.h" 7 | #include "INIReader.h" 8 | #include "telem_client.h" 9 | 10 | #define UNUSED __attribute__((unused)) 11 | 12 | class MAVLink_Writer 13 | { 14 | public: 15 | MAVLink_Writer(INIReader *config UNUSED) 16 | { 17 | } 18 | void send_message(const mavlink_message_t &msg); 19 | 20 | void add_client(Telem_Client *); 21 | bool any_data_to_send(); 22 | 23 | private: 24 | std::vector< Telem_Client * > clients; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/message_handler.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSolo/sololink/89ae7473f3810e7904079e55542fc5ff488dd8f7/flightcode/dataflash_logger/message_handler.cpp -------------------------------------------------------------------------------- /flightcode/dataflash_logger/message_handler.h: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGE_HANDLER_H 2 | #define MESSAGE_HANDLER_H 3 | 4 | #define UNUSED __attribute__((unused)) 5 | 6 | class Message_Handler 7 | { 8 | public: 9 | friend class Format_Reader; 10 | 11 | virtual bool configure(INIReader *config UNUSED) 12 | { 13 | return true; 14 | } 15 | 16 | virtual void sighup_received() 17 | { 18 | } 19 | 20 | virtual void end_of_log(uint32_t packet_count UNUSED) 21 | { 22 | } 23 | 24 | protected: 25 | virtual void idle_tenthHz() 26 | { 27 | } 28 | virtual void idle_1Hz() 29 | { 30 | } 31 | virtual void idle_10Hz() 32 | { 33 | } 34 | virtual void idle_100Hz() 35 | { 36 | } 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/telem_client.cpp: -------------------------------------------------------------------------------- 1 | #include "telem_client.h" 2 | 3 | uint32_t Telem_Client::send_buffer_used() 4 | { 5 | if (_send_buf_stop >= _send_buf_start) { 6 | return _send_buf_stop - _send_buf_start; 7 | } 8 | return send_buf_size() - _send_buf_start + _send_buf_stop; 9 | } 10 | uint32_t Telem_Client::send_buffer_space_free() 11 | { 12 | return send_buf_size() - send_buffer_used(); 13 | } 14 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/telem_client.h: -------------------------------------------------------------------------------- 1 | #ifndef _TELEM_CLIENT_H 2 | #define _TELEM_CLIENT_H 3 | 4 | #include "../mavlink/c_library/ardupilotmega/mavlink.h" 5 | #include 6 | #include "INIReader.h" 7 | 8 | class Telem_Client 9 | { 10 | public: 11 | Telem_Client(uint8_t *recv_buf, uint32_t recv_buflen) 12 | : _recv_buf(recv_buf), _recv_buflen(recv_buflen) 13 | { 14 | } 15 | 16 | virtual void pack_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, 17 | uint8_t &nfds) = 0; 18 | virtual void configure(INIReader *config) = 0; 19 | virtual void handle_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, 20 | uint8_t &nfds) = 0; 21 | 22 | virtual void init() = 0; 23 | 24 | virtual void do_writer_sends() = 0; 25 | virtual bool send_message(const mavlink_message_t &message) = 0; 26 | virtual bool any_data_to_send() = 0; 27 | 28 | virtual uint32_t send_buffer_space_free(); 29 | virtual uint32_t send_buffer_used(); 30 | 31 | uint32_t _send_buf_start = 0; 32 | uint32_t _send_buf_stop = 0; 33 | 34 | // FIXME: scope 35 | uint8_t *_recv_buf; // receive buffer 36 | uint32_t _recv_buflen; // receive buffer len 37 | uint32_t _recv_buflen_content = 0; 38 | 39 | virtual uint32_t send_buf_size() const = 0; 40 | 41 | private: 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/telem_forwarder_client.h: -------------------------------------------------------------------------------- 1 | #include "INIReader.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "telem_client.h" 8 | 9 | class Telem_Forwarder_Client : public Telem_Client 10 | { 11 | public: 12 | Telem_Forwarder_Client(uint8_t *recv_buf, uint32_t recv_buflen) 13 | : Telem_Client(recv_buf, recv_buflen) 14 | { 15 | } 16 | 17 | uint32_t handle_recv(); 18 | void init() override; 19 | 20 | void configure(INIReader *config); 21 | void pack_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, uint8_t &nfds); 22 | void handle_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, uint8_t &nfds); 23 | 24 | void do_writer_sends(); 25 | bool send_message(const mavlink_message_t &msg); 26 | bool any_data_to_send() 27 | { 28 | return _send_buf_start != _send_buf_stop; 29 | } 30 | 31 | private: 32 | int fd_telem_forwarder = -1; 33 | 34 | struct sockaddr_in sa; // our send-from address 35 | struct sockaddr_in sa_tf; /* telem_forwarder's address */ 36 | 37 | void create_and_bind(); 38 | void pack_telem_forwarder_sockaddr(INIReader *config); 39 | bool sane_telem_forwarder_packet(uint8_t *pkt, uint16_t bpktlen); 40 | 41 | /* send buffer stuff: */ 42 | mavlink_message_t _send_buf[256]; // way too bug? 43 | uint32_t send_buf_size() const 44 | { 45 | return 256; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /flightcode/dataflash_logger/telem_serial.h: -------------------------------------------------------------------------------- 1 | #include "INIReader.h" 2 | 3 | #include "telem_client.h" 4 | 5 | class Telem_Serial : public Telem_Client 6 | { 7 | public: 8 | Telem_Serial(uint8_t *recv_buf, uint32_t recv_buflen) : Telem_Client(recv_buf, recv_buflen) 9 | { 10 | } 11 | 12 | uint32_t handle_read(); 13 | 14 | void configure(INIReader *config); 15 | void init() override; 16 | 17 | void pack_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, uint8_t &nfds); 18 | void handle_select_fds(fd_set &fds_read, fd_set &fds_write, fd_set &fds_err, uint8_t &nfds); 19 | 20 | bool send_message(const mavlink_message_t &message); 21 | 22 | void open_serial_port(); 23 | 24 | void do_writer_sends(); 25 | 26 | bool any_data_to_send() 27 | { 28 | return _send_buf_start != _send_buf_stop; 29 | } 30 | 31 | private: 32 | int fd; 33 | 34 | /* send buffer stuff: */ 35 | uint8_t _send_buf[65536]; /* way too big */ 36 | uint32_t send_buf_size() const 37 | { 38 | return 65536; 39 | } 40 | 41 | std::string serialPortName; 42 | uint32_t serialBaud; 43 | bool serialFlow; 44 | }; 45 | -------------------------------------------------------------------------------- /flightcode/dflog/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util 13 | 14 | INCS = -I../util 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) 18 | 19 | LIBS += -lpthread 20 | 21 | SRCS_CPP = dflog_downloader.cpp 22 | SRCS_C += util.c 23 | 24 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 25 | 26 | MAIN = dflog 27 | 28 | all: $(MAIN) 29 | 30 | $(MAIN): $(OBJS) 31 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 32 | 33 | clean: 34 | $(RM) *.o *~ $(MAIN) 35 | $(RM) ../util/*.o 36 | 37 | BASE := ../.. 38 | 39 | fmt: 40 | @python $(BASE)/tools/build/clang-format-run.py --apply 41 | 42 | fmt-diff: 43 | @python $(BASE)/tools/build/clang-format-run.py 44 | 45 | .PHONY: all clean fmt fmt-diff 46 | -------------------------------------------------------------------------------- /flightcode/dflog/loadLog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import subprocess 4 | import sys 5 | import os 6 | import time 7 | from pymavlink import mavutil 8 | import glob 9 | import ConfigParser 10 | import shutil 11 | from datetime import datetime 12 | import argparse 13 | 14 | SELECT_GPIO = "21" 15 | ENABLE_GPIO = "19" 16 | 17 | #GPIO direction set 18 | def setGPIODir(gpio, direction): 19 | dir_fd = open("/sys/class/gpio/gpio"+str(gpio)+"/direction", "w") 20 | dir_fd.write(direction) 21 | dir_fd.close() 22 | 23 | #Open the GPIO 24 | def openGPIO(gpio): 25 | #Check and see if the GPIO is already exported 26 | if not os.path.isdir("/sys/class/gpio/gpio"+str(gpio)): 27 | #otherwise export it 28 | exp_fd = open("/sys/class/gpio/export", "w") 29 | exp_fd.write(gpio) 30 | exp_fd.close() 31 | 32 | setGPIODir(gpio, "out"); 33 | 34 | def closeGPIO(gpio): 35 | unexp_fd = open("/sys/class/gpio/unexport", "w") 36 | unexp_fd.write(gpio) 37 | unexp_fd.close() 38 | 39 | def setGPIO(gpio, value): 40 | val_fd = open("/sys/class/gpio/gpio"+str(gpio)+"/value", "w") 41 | val_fd.write(value) 42 | val_fd.close() 43 | 44 | def openSetClose(gpio, value): 45 | openGPIO(gpio) 46 | setGPIO(gpio, value) 47 | closeGPIO(gpio) 48 | 49 | #Set the GPIO low 50 | def disconnectAndExit(): 51 | openSetClose(SELECT_GPIO, "0") 52 | openSetClose(ENABLE_GPIO, "1") 53 | sys.exit() 54 | 55 | parser = argparse.ArgumentParser() 56 | parser.add_argument("lognum", help="Log number to download, or 'latest'") 57 | args = parser.parse_args() 58 | 59 | #Log downloading process 60 | print "Pixhawk log loader" 61 | 62 | #Set the USB select GPIOs 63 | openSetClose(SELECT_GPIO, "1") 64 | openSetClose(ENABLE_GPIO, "0") 65 | time.sleep(1) 66 | 67 | print "Checking for pixhawk on USB" 68 | 69 | usb_devs = glob.glob('/dev/serial/by-id/usb-3D*') 70 | if not usb_devs: 71 | print "No pixhawk found on USB. Exiting." 72 | disconnectAndExit() 73 | 74 | print "Pixhawk found on USB, requesting log." 75 | pixhawk_usb = usb_devs[-1] 76 | m = mavutil.mavlink_connection(pixhawk_usb) 77 | 78 | #Call the log downloader app 79 | ret = subprocess.call(["dflog", str(args.lognum)]) 80 | 81 | disconnectAndExit() 82 | 83 | -------------------------------------------------------------------------------- /flightcode/hostapd_ctrl/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util 13 | 14 | INCS = -I../util 15 | 16 | CFLAGS += -Wall $(INCS) 17 | 18 | SRCS_C = main.c hostapd_ctrl.c util.c 19 | 20 | OBJS = $(SRCS_C:.c=.o) 21 | 22 | MAIN = hostapd_ctrl 23 | 24 | all: $(MAIN) 25 | 26 | $(MAIN): $(OBJS) 27 | $(LINK.c) -o $(MAIN) $(OBJS) $(LIBS) 28 | 29 | clean: 30 | $(RM) *.o *~ $(MAIN) 31 | 32 | BASE := ../.. 33 | 34 | fmt: 35 | @python $(BASE)/tools/build/clang-format-run.py --apply 36 | 37 | fmt-diff: 38 | @python $(BASE)/tools/build/clang-format-run.py 39 | 40 | .PHONY: all clean fmt fmt-diff 41 | -------------------------------------------------------------------------------- /flightcode/hostapd_ctrl/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "util.h" 7 | #include "hostapd_ctrl.h" 8 | 9 | /* Test program for hostapd_ctrl */ 10 | 11 | /* make this small (e.g. 2) to test the table-too-small case */ 12 | #define STATIONS_MAX 10 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | void *handle; 17 | hostapd_station_info_t station_info[STATIONS_MAX]; 18 | int stations; 19 | int i; 20 | char mac_string[MAC_STRING_LEN]; 21 | 22 | handle = hostapd_ctrl_new("wlan0-ap"); 23 | if (handle == NULL) { 24 | printf("ERROR creating control connection\n"); 25 | exit(1); 26 | } 27 | 28 | stations = STATIONS_MAX; 29 | if (hostapd_ctrl_get_stations(handle, station_info, &stations) != 0) { 30 | printf("ERROR getting station info\n"); 31 | hostapd_ctrl_delete(handle); 32 | exit(1); 33 | } 34 | 35 | printf("%d stations:\n", stations); 36 | 37 | if (stations > STATIONS_MAX) 38 | /* there are more stations than would fit in the table we supplied */ 39 | stations = STATIONS_MAX; 40 | 41 | for (i = 0; i < stations; i++) 42 | printf("%s\n", mac_ntoa(station_info[i].mac, mac_string)); 43 | 44 | hostapd_ctrl_delete(handle); 45 | 46 | exit(0); 47 | 48 | } /* main */ 49 | -------------------------------------------------------------------------------- /flightcode/ini/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | 4 | clean: 5 | 6 | BASE := ../.. 7 | 8 | fmt: 9 | @python $(BASE)/tools/build/clang-format-run.py --apply 10 | 11 | fmt-diff: 12 | @python $(BASE)/tools/build/clang-format-run.py 13 | 14 | .PHONY: all clean fmt fmt-diff 15 | -------------------------------------------------------------------------------- /flightcode/ini/cpp/INIReader.cpp: -------------------------------------------------------------------------------- 1 | // Read an INI file into easy-to-access name/value pairs. 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../ini.h" 7 | #include "INIReader.h" 8 | 9 | using std::string; 10 | 11 | INIReader::INIReader(string filename) 12 | { 13 | _error = ini_parse(filename.c_str(), ValueHandler, this); 14 | } 15 | 16 | int INIReader::ParseError() 17 | { 18 | return _error; 19 | } 20 | 21 | string INIReader::Get(string section, string name, string default_value) 22 | { 23 | string key = MakeKey(section, name); 24 | return _values.count(key) ? _values[key] : default_value; 25 | } 26 | 27 | long INIReader::GetInteger(string section, string name, long default_value) 28 | { 29 | string valstr = Get(section, name, ""); 30 | const char *value = valstr.c_str(); 31 | char *end; 32 | // This parses "1234" (decimal) and also "0x4D2" (hex) 33 | long n = strtol(value, &end, 0); 34 | return end > value ? n : default_value; 35 | } 36 | 37 | double INIReader::GetReal(string section, string name, double default_value) 38 | { 39 | string valstr = Get(section, name, ""); 40 | const char *value = valstr.c_str(); 41 | char *end; 42 | double n = strtod(value, &end); 43 | return end > value ? n : default_value; 44 | } 45 | 46 | bool INIReader::GetBoolean(string section, string name, bool default_value) 47 | { 48 | string valstr = Get(section, name, ""); 49 | // Convert to lower case to make string comparisons case-insensitive 50 | std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower); 51 | if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1") 52 | return true; 53 | else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0") 54 | return false; 55 | else 56 | return default_value; 57 | } 58 | 59 | string INIReader::MakeKey(string section, string name) 60 | { 61 | string key = section + "." + name; 62 | // Convert to lower case to make section/name lookups case-insensitive 63 | std::transform(key.begin(), key.end(), key.begin(), ::tolower); 64 | return key; 65 | } 66 | 67 | int INIReader::ValueHandler(void *user, const char *section, const char *name, const char *value) 68 | { 69 | INIReader *reader = (INIReader *)user; 70 | string key = MakeKey(section, name); 71 | if (reader->_values[key].size() > 0) 72 | reader->_values[key] += "\n"; 73 | reader->_values[key] += value; 74 | return 1; 75 | } 76 | -------------------------------------------------------------------------------- /flightcode/ini/cpp/INIReader.h: -------------------------------------------------------------------------------- 1 | // Read an INI file into easy-to-access name/value pairs. 2 | 3 | // inih and INIReader are released under the New BSD license (see LICENSE.txt). 4 | // Go to the project home page for more info: 5 | // 6 | // http://code.google.com/p/inih/ 7 | 8 | #ifndef __INIREADER_H__ 9 | #define __INIREADER_H__ 10 | 11 | #include 12 | #include 13 | 14 | // Read an INI file into easy-to-access name/value pairs. (Note that I've gone 15 | // for simplicity here rather than speed, but it should be pretty decent.) 16 | class INIReader 17 | { 18 | public: 19 | // Construct INIReader and parse given filename. See ini.h for more info 20 | // about the parsing. 21 | INIReader(std::string filename); 22 | 23 | // Return the result of ini_parse(), i.e., 0 on success, line number of 24 | // first error on parse error, or -1 on file open error. 25 | int ParseError(); 26 | 27 | // Get a string value from INI file, returning default_value if not found. 28 | std::string Get(std::string section, std::string name, std::string default_value); 29 | 30 | // Get an integer (long) value from INI file, returning default_value if 31 | // not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2"). 32 | long GetInteger(std::string section, std::string name, long default_value); 33 | 34 | // Get a real (floating point double) value from INI file, returning 35 | // default_value if not found or not a valid floating point value 36 | // according to strtod(). 37 | double GetReal(std::string section, std::string name, double default_value); 38 | 39 | // Get a boolean value from INI file, returning default_value if not found or if 40 | // not a valid true/false value. Valid true values are "true", "yes", "on", "1", 41 | // and valid false values are "false", "no", "off", "0" (not case sensitive). 42 | bool GetBoolean(std::string section, std::string name, bool default_value); 43 | 44 | private: 45 | int _error; 46 | std::map< std::string, std::string > _values; 47 | static std::string MakeKey(std::string section, std::string name); 48 | static int ValueHandler(void *user, const char *section, const char *name, const char *value); 49 | }; 50 | 51 | #endif // __INIREADER_H__ 52 | -------------------------------------------------------------------------------- /flightcode/ini/cpp/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | 4 | clean: 5 | 6 | BASE := ../../.. 7 | 8 | fmt: 9 | @python $(BASE)/tools/build/clang-format-run.py --apply 10 | 11 | fmt-diff: 12 | @python $(BASE)/tools/build/clang-format-run.py 13 | 14 | .PHONY: all clean fmt fmt-diff 15 | -------------------------------------------------------------------------------- /flightcode/ini/ini.h: -------------------------------------------------------------------------------- 1 | /* inih -- simple .INI file parser 2 | 3 | inih is released under the New BSD license (see LICENSE.txt). Go to the project 4 | home page for more info: 5 | 6 | http://code.google.com/p/inih/ 7 | 8 | */ 9 | 10 | #ifndef __INI_H__ 11 | #define __INI_H__ 12 | 13 | /* Make this header file easier to include in C++ code */ 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #include 19 | 20 | /* Parse given INI-style file. May have [section]s, name=value pairs 21 | (whitespace stripped), and comments starting with ';' (semicolon). Section 22 | is "" if name=value pair parsed before any section heading. name:value 23 | pairs are also supported as a concession to Python's ConfigParser. 24 | 25 | For each name=value pair parsed, call handler function with given user 26 | pointer as well as section, name, and value (data only valid for duration 27 | of handler call). Handler should return nonzero on success, zero on error. 28 | 29 | Returns 0 on success, line number of first error on parse error (doesn't 30 | stop on first error), -1 on file open error, or -2 on memory allocation 31 | error (only when INI_USE_STACK is zero). 32 | */ 33 | int ini_parse(const char *filename, 34 | int (*handler)(void *user, const char *section, const char *name, const char *value), 35 | void *user); 36 | 37 | /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't 38 | close the file when it's finished -- the caller must do that. */ 39 | int ini_parse_file(FILE *file, int (*handler)(void *user, const char *section, const char *name, 40 | const char *value), 41 | void *user); 42 | 43 | /* Nonzero to allow multi-line value parsing, in the style of Python's 44 | ConfigParser. If allowed, ini_parse() will call the handler with the same 45 | name for each subsequent line parsed. */ 46 | #ifndef INI_ALLOW_MULTILINE 47 | #define INI_ALLOW_MULTILINE 1 48 | #endif 49 | 50 | /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of 51 | the file. See http://code.google.com/p/inih/issues/detail?id=21 */ 52 | #ifndef INI_ALLOW_BOM 53 | #define INI_ALLOW_BOM 1 54 | #endif 55 | 56 | /* Nonzero to use stack, zero to use heap (malloc/free). */ 57 | #ifndef INI_USE_STACK 58 | #define INI_USE_STACK 1 59 | #endif 60 | 61 | /* Stop parsing on first error (default is to keep parsing). */ 62 | #ifndef INI_STOP_ON_FIRST_ERROR 63 | #define INI_STOP_ON_FIRST_ERROR 0 64 | #endif 65 | 66 | /* Maximum line length for any line in INI file. */ 67 | #ifndef INI_MAX_LINE 68 | #define INI_MAX_LINE 200 69 | #endif 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | 75 | #endif /* __INI_H__ */ 76 | -------------------------------------------------------------------------------- /flightcode/log/Log.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOG_H 2 | #define _LOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | /********************************************************************** 11 | Class: Log 12 | 13 | Description: A simple logging class. Opens a logfile specified by the 14 | calling function. The log file can be rolled when its 15 | size gets large enough, out to maxLogFiles files. 16 | ***********************************************************************/ 17 | class Log 18 | { 19 | public: 20 | Log(string filename, long int maxFileSize, int maxLogFiles); 21 | Log(string filename, long int maxFileSize, int maxLogFiles, bool newLogOnBoot); 22 | void checkSizeAndRoll(void); 23 | void forceRoll(void); 24 | 25 | // Left as a public for use in logging macros 26 | const char *getTimeString(void); 27 | 28 | // Leave the file descriptor public so it can be written to 29 | // by the calling application. 30 | ofstream log_fd; 31 | 32 | private: 33 | long int _maxFileSize; 34 | int _maxLogFiles; 35 | string _logFilename; 36 | 37 | bool doesFileExist(string filename); 38 | long int getFilesize(string filename); 39 | }; 40 | 41 | #endif //_LOG_H 42 | -------------------------------------------------------------------------------- /flightcode/log/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | 4 | clean: 5 | 6 | BASE := ../.. 7 | 8 | fmt: 9 | @python $(BASE)/tools/build/clang-format-run.py --apply 10 | 11 | fmt-diff: 12 | @python $(BASE)/tools/build/clang-format-run.py 13 | 14 | .PHONY: all clean fmt fmt-diff 15 | -------------------------------------------------------------------------------- /flightcode/mavlink/c_library/ardupilotmega/mavlink.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @brief MAVLink comm protocol built from ardupilotmega.xml 3 | * @see http://mavlink.org 4 | */ 5 | #ifndef MAVLINK_H 6 | #define MAVLINK_H 7 | 8 | #ifndef MAVLINK_STX 9 | #define MAVLINK_STX 254 10 | #endif 11 | 12 | #ifndef MAVLINK_ENDIAN 13 | #define MAVLINK_ENDIAN MAVLINK_LITTLE_ENDIAN 14 | #endif 15 | 16 | #ifndef MAVLINK_ALIGNED_FIELDS 17 | #define MAVLINK_ALIGNED_FIELDS 1 18 | #endif 19 | 20 | #ifndef MAVLINK_CRC_EXTRA 21 | #define MAVLINK_CRC_EXTRA 1 22 | #endif 23 | 24 | #include "version.h" 25 | #include "ardupilotmega.h" 26 | 27 | #endif // MAVLINK_H 28 | -------------------------------------------------------------------------------- /flightcode/mavlink/c_library/ardupilotmega/version.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @brief MAVLink comm protocol built from ardupilotmega.xml 3 | * @see http://mavlink.org 4 | */ 5 | #ifndef MAVLINK_VERSION_H 6 | #define MAVLINK_VERSION_H 7 | 8 | #define MAVLINK_BUILD_DATE "Fri Jan 29 13:57:54 2016" 9 | #define MAVLINK_WIRE_PROTOCOL_VERSION "1.0" 10 | #define MAVLINK_MAX_DIALECT_PAYLOAD_SIZE 255 11 | 12 | #endif // MAVLINK_VERSION_H 13 | -------------------------------------------------------------------------------- /flightcode/mavlink/c_library/checksum.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" { 3 | #endif 4 | 5 | #ifndef _CHECKSUM_H_ 6 | #define _CHECKSUM_H_ 7 | 8 | // Visual Studio versions before 2010 don't have stdint.h, so we just error out. 9 | #if (defined _MSC_VER) && (_MSC_VER < 1600) 10 | #error "The C-MAVLink implementation requires Visual Studio 2010 or greater" 11 | #endif 12 | 13 | #include 14 | 15 | /** 16 | * 17 | * CALCULATE THE CHECKSUM 18 | * 19 | */ 20 | 21 | #define X25_INIT_CRC 0xffff 22 | #define X25_VALIDATE_CRC 0xf0b8 23 | 24 | #ifndef HAVE_CRC_ACCUMULATE 25 | /** 26 | * @brief Accumulate the X.25 CRC by adding one char at a time. 27 | * 28 | * The checksum function adds the hash of one char at a time to the 29 | * 16 bit checksum (uint16_t). 30 | * 31 | * @param data new char to hash 32 | * @param crcAccum the already accumulated checksum 33 | **/ 34 | static inline void crc_accumulate(uint8_t data, uint16_t *crcAccum) 35 | { 36 | /*Accumulate one byte of data into the CRC*/ 37 | uint8_t tmp; 38 | 39 | tmp = data ^ (uint8_t)(*crcAccum &0xff); 40 | tmp ^= (tmp<<4); 41 | *crcAccum = (*crcAccum>>8) ^ (tmp<<8) ^ (tmp <<3) ^ (tmp>>4); 42 | } 43 | #endif 44 | 45 | 46 | /** 47 | * @brief Initiliaze the buffer for the X.25 CRC 48 | * 49 | * @param crcAccum the 16 bit X.25 CRC 50 | */ 51 | static inline void crc_init(uint16_t* crcAccum) 52 | { 53 | *crcAccum = X25_INIT_CRC; 54 | } 55 | 56 | 57 | /** 58 | * @brief Calculates the X.25 checksum on a byte buffer 59 | * 60 | * @param pBuffer buffer containing the byte array to hash 61 | * @param length length of the byte array 62 | * @return the checksum over the buffer bytes 63 | **/ 64 | static inline uint16_t crc_calculate(const uint8_t* pBuffer, uint16_t length) 65 | { 66 | uint16_t crcTmp; 67 | crc_init(&crcTmp); 68 | while (length--) { 69 | crc_accumulate(*pBuffer++, &crcTmp); 70 | } 71 | return crcTmp; 72 | } 73 | 74 | 75 | /** 76 | * @brief Accumulate the X.25 CRC by adding an array of bytes 77 | * 78 | * The checksum function adds the hash of one char at a time to the 79 | * 16 bit checksum (uint16_t). 80 | * 81 | * @param data new bytes to hash 82 | * @param crcAccum the already accumulated checksum 83 | **/ 84 | static inline void crc_accumulate_buffer(uint16_t *crcAccum, const char *pBuffer, uint16_t length) 85 | { 86 | const uint8_t *p = (const uint8_t *)pBuffer; 87 | while (length--) { 88 | crc_accumulate(*p++, crcAccum); 89 | } 90 | } 91 | 92 | #endif /* _CHECKSUM_H_ */ 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | -------------------------------------------------------------------------------- /flightcode/mavlink/c_library/common/mavlink.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @brief MAVLink comm protocol built from common.xml 3 | * @see http://mavlink.org 4 | */ 5 | #ifndef MAVLINK_H 6 | #define MAVLINK_H 7 | 8 | #ifndef MAVLINK_STX 9 | #define MAVLINK_STX 254 10 | #endif 11 | 12 | #ifndef MAVLINK_ENDIAN 13 | #define MAVLINK_ENDIAN MAVLINK_LITTLE_ENDIAN 14 | #endif 15 | 16 | #ifndef MAVLINK_ALIGNED_FIELDS 17 | #define MAVLINK_ALIGNED_FIELDS 1 18 | #endif 19 | 20 | #ifndef MAVLINK_CRC_EXTRA 21 | #define MAVLINK_CRC_EXTRA 1 22 | #endif 23 | 24 | #include "version.h" 25 | #include "common.h" 26 | 27 | #endif // MAVLINK_H 28 | -------------------------------------------------------------------------------- /flightcode/mavlink/c_library/common/version.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * @brief MAVLink comm protocol built from common.xml 3 | * @see http://mavlink.org 4 | */ 5 | #ifndef MAVLINK_VERSION_H 6 | #define MAVLINK_VERSION_H 7 | 8 | #define MAVLINK_BUILD_DATE "Fri Jan 29 13:57:56 2016" 9 | #define MAVLINK_WIRE_PROTOCOL_VERSION "1.0" 10 | #define MAVLINK_MAX_DIALECT_PAYLOAD_SIZE 255 11 | 12 | #endif // MAVLINK_VERSION_H 13 | -------------------------------------------------------------------------------- /flightcode/mavlink/generate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() { 4 | echo "usage: generate " 5 | exit 1 6 | } 7 | 8 | if [ -z "${1}" ]; then 9 | echo "argument expected" 10 | usage 11 | fi 12 | 13 | if [ ! -d "${1}/message_definitions" ]; then 14 | echo "${1}/message_definitions not found" 15 | usage 16 | fi 17 | 18 | outdir=`pwd`/c_library 19 | 20 | pushd ${1} 21 | 22 | python -m pymavlink.tools.mavgen --lang C -o ${outdir} \ 23 | message_definitions/v1.0/ardupilotmega.xml 24 | 25 | if which git; then 26 | git log --oneline > ${outdir}/.generate 27 | else 28 | echo "git not found" > ${outdir}/.generate 29 | fi 30 | 31 | popd 32 | -------------------------------------------------------------------------------- /flightcode/mavpkt/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util ../mavlink/c_library/ardupilotmega 13 | 14 | INCS = -I../util -I../mavlink/c_library/ardupilotmega 15 | 16 | CFLAGS += -Wall -O2 $(INCS) 17 | CXXFLAGS += -Wall -O2 $(INCS) 18 | 19 | SRCS_CPP = mavpkt.cpp 20 | SRCS_C = util.c 21 | 22 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 23 | 24 | MAIN = mavpkt 25 | 26 | all: $(MAIN) 27 | 28 | $(MAIN): $(OBJS) 29 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 30 | 31 | clean: 32 | $(RM) *.o *~ $(MAIN) 33 | 34 | .PHONY: clean 35 | -------------------------------------------------------------------------------- /flightcode/old/runMavproxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The goal is to use netcat to run MAVProxy as a server so we can connect to 4 | # its console on a tcp port. This does not quite work; one can connect to the 5 | # port from a remote host, but the input and/or output is getting buffered 6 | # somewhere such that output does not show up until the connection is being 7 | # closed, then it all comes at once. 8 | 9 | # In any case, we don't want MAVProxy on the console tty when running from 10 | # init, so this at least serves that purpose. 11 | 12 | # mavproxy not starting up when run by netcat... 13 | #nc -l -p 5020 -e 14 | 15 | mavproxy.py \ 16 | --master=/dev/ttymxc1,57600 --rtscts \ 17 | --out=10.1.1.1:14550 18 | 19 | # XXX bogs down the telemetry stream 20 | # --load-module=solo \ 21 | -------------------------------------------------------------------------------- /flightcode/old/simple_stats.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class SimpleStats: 4 | 5 | def __init__(self): 6 | self.reset() 7 | 8 | def reset(self): 9 | self._count = 0 10 | self._sum_x = 0.0 11 | self._sum_x2 = 0.0 12 | self._max_x = None 13 | self._min_x = None 14 | 15 | def update(self, x): 16 | self._count += 1 17 | self._sum_x += x 18 | self._sum_x2 += (x * x) 19 | if self._max_x is None or self._max_x < x: 20 | self._max_x = float(x) 21 | if self._min_x is None or self._min_x > x: 22 | self._min_x = float(x) 23 | 24 | # always returns int 25 | def count(self): 26 | return self._count 27 | 28 | # always returns float 29 | def max(self): 30 | return self._max_x 31 | 32 | # always returns float 33 | def min(self): 34 | return self._min_x 35 | 36 | # always returns float 37 | def average(self): 38 | if(self._count > 0): 39 | return float(self._sum_x / self._count) 40 | else: 41 | return 0 42 | 43 | # always returns float 44 | def stdev(self): 45 | avg = self.average() 46 | if(self._count > 0): 47 | return math.sqrt(self._sum_x2 / self._count - avg * avg) 48 | else: 49 | return 0 50 | -------------------------------------------------------------------------------- /flightcode/pixrc/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util ../command ../ini ../ini/cpp ../log 13 | 14 | INCS = -I../util -I../command -I../ini -I../ini/cpp -I../log 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) 18 | 19 | LIBS = -lpthread -lrt 20 | 21 | SRCS_CPP = pixrc.cpp 22 | SRCS_CPP += Commander.cpp 23 | SRCS_CPP += RcCommander.cpp 24 | SRCS_CPP += RcLock.cpp 25 | SRCS_CPP += INIReader.cpp Log.cpp 26 | SRCS_C = util.c mutex.c ini.c rc_ipc.c net_stats.c 27 | SRCS_C += file_util.c 28 | SRCS_C += syslog.c 29 | 30 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 31 | 32 | MAIN = pixrc 33 | 34 | all: $(MAIN) 35 | 36 | $(MAIN): $(OBJS) 37 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 38 | 39 | clean: 40 | $(RM) *.o *~ $(MAIN) 41 | $(RM) ../ini/*.o 42 | $(RM) ../ini/cpp/*.o 43 | $(RM) ../log/*.o 44 | 45 | BASE := ../.. 46 | 47 | fmt: 48 | @python $(BASE)/tools/build/clang-format-run.py --apply 49 | 50 | fmt-diff: 51 | @python $(BASE)/tools/build/clang-format-run.py 52 | 53 | .PHONY: clean 54 | -------------------------------------------------------------------------------- /flightcode/pixrc/RcCommander.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "RcCommander.h" 14 | 15 | using namespace std; 16 | 17 | // Handle ATTACH or DETACH command. 18 | // 19 | // This overrides Commander::handle_attach() to allow for attaching/detaching 20 | // the RC uplink. If the optional argument does not specify the uplink (or is 21 | // not present), Commander::handle_attach() is called to take care of things. 22 | void RcCommander::handle_attach(const struct sockaddr *src_addr, socklen_t src_addr_len, 23 | const char *client, bool attach) 24 | { 25 | 26 | // If the optional argument is not present or does not specify the uplink 27 | // Commander::handle_attach() is called to take care of things. 28 | if (client == NULL || strcasecmp(client, "UPLINK") != 0) { 29 | Commander::handle_attach(src_addr, src_addr_len, client, attach); 30 | } else { 31 | // Attach/detach the uplink 32 | uplink_attached = attach; 33 | 34 | if (uplink_attached) 35 | syslog(LOG_INFO, "cmd: uplink attached"); 36 | else 37 | syslog(LOG_INFO, "cmd: uplink detached"); 38 | 39 | send_response(src_addr, src_addr_len, "OK\n"); 40 | } 41 | 42 | } // RcCommander::handle_attach 43 | -------------------------------------------------------------------------------- /flightcode/pixrc/RcCommander.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "Commander.h" 4 | 5 | class RcCommander : public Commander 6 | { 7 | public: 8 | RcCommander(const char *sock_name) : Commander(sock_name), uplink_attached(true){}; 9 | 10 | inline bool is_attached(void) 11 | { 12 | return uplink_attached; 13 | } 14 | 15 | protected: 16 | // override attach/detach to handle the special case of attaching 17 | // or detaching the RC uplink 18 | virtual void handle_attach(const struct sockaddr *, socklen_t, const char *, bool); 19 | 20 | private: 21 | bool uplink_attached; 22 | 23 | }; // class RcCommander 24 | -------------------------------------------------------------------------------- /flightcode/pixrc/rc_ipc.h: -------------------------------------------------------------------------------- 1 | #ifndef RC_IPC_H 2 | #define RC_IPC_H 3 | 4 | /* 5 | * Definitions supporting IPC sharing of RC packets. Internally, there 6 | * is a shared memory containing an RC packet (rc_pkt.h) and a semaphore 7 | * controlling access. 8 | */ 9 | 10 | #include "rc_pkt.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | extern void *rc_ipc_attach(int verbosity); 17 | 18 | extern int rc_ipc_put(void *rc_ipc_id, const struct rc_pkt *pkt, int verbosity); 19 | 20 | extern int rc_ipc_get(void *rc_ipc_id, struct rc_pkt *pkt, int verbosity); 21 | 22 | extern int rc_ipc_detach(void *rc_ipc_id, int verbosity); 23 | 24 | #ifdef __cplusplus 25 | }; 26 | #endif 27 | 28 | #endif /* RC_IPC_H */ 29 | -------------------------------------------------------------------------------- /flightcode/pixrc/rc_pkt.h: -------------------------------------------------------------------------------- 1 | #ifndef RC_PKT_H 2 | #define RC_PKT_H 3 | 4 | /* 5 | * This is the RC packet structure as found in shared memory on Solo. 6 | * At startup, it is written by the pixrc process, UDP_task. At runtime, it 7 | * may be switched to be updated by some other flight-control process. It is 8 | * always read by the pixrc process, serial_task, which converts it to DSM and 9 | * writes it to the Pixhawk. 10 | */ 11 | 12 | #include 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #define NUM_CHANNELS 8 19 | 20 | struct __attribute((__packed__)) rc_pkt { 21 | uint64_t timestamp; 22 | uint16_t sequence; 23 | uint16_t channel[NUM_CHANNELS]; 24 | }; 25 | 26 | #ifdef __cplusplus 27 | }; 28 | #endif 29 | 30 | #endif /* RC_PKT_H */ 31 | -------------------------------------------------------------------------------- /flightcode/pixrc/test_pixrc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "util.h" 13 | 14 | using namespace std; 15 | 16 | /*********************************************************************** 17 | UDP macros 18 | ***********************************************************************/ 19 | #define UDP_PORT 5005 20 | #define NUM_CHANNELS 8 21 | 22 | int main(void) 23 | { 24 | int sock_fd; 25 | struct sockaddr_in remaddr; /* server address */ 26 | int slen = sizeof(remaddr); 27 | char *server = "10.1.1.10"; 28 | // char *server = "127.0.0.1"; /* change this to use a different server */ 29 | uint16_t channelVals[NUM_CHANNELS] = {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500}; 30 | uint16_t sequence = 0; 31 | uint64_t timestamp = 0; 32 | uint64_t last_us, now_us; 33 | char buf[512]; 34 | int delta; 35 | struct sched_param param; 36 | 37 | srand(time(NULL)); 38 | 39 | if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 40 | cerr << "cannot create socket" << endl; 41 | return 0; 42 | } 43 | 44 | int tos_local = 0xFF; 45 | setsockopt(sock_fd, IPPROTO_IP, IP_TOS, &tos_local, sizeof(tos_local)); 46 | 47 | memset((char *)&remaddr, 0, sizeof(remaddr)); 48 | remaddr.sin_family = AF_INET; 49 | remaddr.sin_port = htons(UDP_PORT); 50 | if (inet_aton(server, &remaddr.sin_addr) == 0) { 51 | cerr << "inet_aton() failed" << endl; 52 | return 0; 53 | } 54 | 55 | memset(¶m, 0, sizeof(param)); 56 | param.sched_priority = sched_get_priority_max(SCHED_FIFO); 57 | pthread_setschedparam(0, SCHED_FIFO, ¶m); 58 | 59 | last_us = clock_gettime_us(CLOCK_MONOTONIC); 60 | 61 | while (true) { 62 | now_us = clock_gettime_us(CLOCK_MONOTONIC); 63 | delta = now_us - last_us; 64 | if (delta > 21000) 65 | cout << "Slow! " << delta << "us" << endl; 66 | last_us = now_us; 67 | memset(buf, 0, sizeof(buf)); 68 | memcpy(buf, ×tamp, 8); 69 | memcpy(&buf[8], &sequence, 2); 70 | memcpy(&buf[10], channelVals, 16); 71 | 72 | /* now let's send the messages */ 73 | if (sendto(sock_fd, buf, 26, 0, (struct sockaddr *)&remaddr, slen) == -1) { 74 | cerr << "sendto failed" << endl; 75 | return 0; 76 | } 77 | 78 | timestamp += 1; 79 | sequence += 1; 80 | 81 | uint64_t delay = 20000; // + (rand() % 10000 - 5000); 82 | usleep(delay); 83 | } 84 | 85 | close(sock_fd); 86 | return 1; 87 | } 88 | -------------------------------------------------------------------------------- /flightcode/proc_top/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util 13 | 14 | INCS = -I../util 15 | 16 | CFLAGS += -Wall $(INCS) 17 | 18 | SRCS_C = main.c proc_table.c util.c 19 | 20 | OBJS = $(SRCS_C:.c=.o) 21 | 22 | MAIN = proc_top 23 | 24 | all: $(MAIN) 25 | 26 | $(MAIN): $(OBJS) 27 | $(LINK.c) -o $(MAIN) $(OBJS) $(LIBS) 28 | 29 | clean: 30 | $(RM) *.o *~ $(MAIN) 31 | 32 | BASE := ../.. 33 | 34 | fmt: 35 | @python $(BASE)/tools/build/clang-format-run.py --apply 36 | 37 | fmt-diff: 38 | @python $(BASE)/tools/build/clang-format-run.py 39 | 40 | .PHONY: all clean fmt fmt-diff 41 | -------------------------------------------------------------------------------- /flightcode/python/ath9k.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | import sys 5 | import time 6 | #sys.path.append("/usr/bin") 7 | #import clock 8 | 9 | 10 | # This takes ~20 msec 11 | # (VO): qnum: 3 qdepth: 0 ampdu-depth: 0 pending: 0 stopped: 0 12 | r = re.compile(\ 13 | "\ 14 | \((.+)\):\ 15 | +([a-z-]+): +([0-9]+)\ 16 | +([a-z-]+): +([0-9]+)\ 17 | +([a-z-]+): +([0-9]+)\ 18 | +([a-z-]+): +([0-9]+)\ 19 | +([a-z-]+): +([0-9]+)\ 20 | ") 21 | 22 | 23 | def get_queues(): 24 | try: 25 | f = open("/sys/kernel/debug/ieee80211/phy0/ath9k/queues") 26 | except: 27 | return None 28 | s = f.read() 29 | f.close() 30 | s = s.splitlines() 31 | d = { } 32 | for line in s: 33 | m = r.match(line) 34 | v = { } 35 | v[m.group(2)] = int(m.group(3)) 36 | v[m.group(4)] = int(m.group(5)) 37 | v[m.group(6)] = int(m.group(7)) 38 | v[m.group(8)] = int(m.group(9)) 39 | v[m.group(10)] = int(m.group(11)) 40 | d[m.group(1)] = v 41 | return d 42 | 43 | 44 | graph = True 45 | 46 | if __name__ == "__main__": 47 | last = { } 48 | count = 0 49 | while True: 50 | qs = get_queues() 51 | if graph: 52 | if count == 0: 53 | line = ['-'] * 128 54 | count = 9 55 | else: 56 | line = [' '] * 128 57 | count -= 1 58 | for c in range(7): 59 | line[c * 20] = '|' 60 | for q in qs: 61 | val = qs[q]['pending'] 62 | if val > 127: 63 | val = 127 64 | #print q, qs[q], str(qs[q]), str(qs[q])[1] 65 | line[val] = q[1] 66 | print "".join(line) 67 | else: 68 | for q in qs: 69 | # if too many packets pending twice in a row, print message 70 | if q in last and last[q] > 120 and qs[q]['pending'] > 120: 71 | print q, last[q], qs[q]['pending'] 72 | last[q] = qs[q]['pending'] 73 | time.sleep(0.1) 74 | -------------------------------------------------------------------------------- /flightcode/python/gpio.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def export(gpio): 5 | # is GPIO already exported? 6 | if os.path.isdir("/sys/class/gpio/gpio" + str(gpio)): 7 | return 8 | # no, export it 9 | f = open("/sys/class/gpio/export", "w") 10 | f.write(str(gpio)) 11 | f.close() 12 | 13 | 14 | def unexport(gpio): 15 | f = open("/sys/class/gpio/unexport", "w") 16 | f.write(str(gpio)) 17 | f.close() 18 | 19 | 20 | # set direction 21 | # gpio is a string or integer (e.g. "21" or 21) 22 | # direction is "in" or "out" 23 | def set_dir(gpio, direction): 24 | filename = "/sys/class/gpio/gpio%s/direction" % str(gpio) 25 | try: 26 | f = open(filename, "w") 27 | except: 28 | print "error opening %s (need to export first?)" % filename 29 | return 30 | f.write(direction) 31 | f.close() 32 | 33 | 34 | # set output value 35 | # gpio is a string or integer (e.g. "21" or 21) 36 | # value is a string or integer ("0", "1", 0, 1) 37 | def set(gpio, value): 38 | filename = "/sys/class/gpio/gpio%s/value" % str(gpio) 39 | try: 40 | f = open(filename, "w") 41 | except: 42 | print "error opening %s (need to export first?)" % filename 43 | return 44 | try: 45 | f.write(str(value)) 46 | f.close() 47 | except: 48 | print "error setting %s (is it an output?)" % filename 49 | -------------------------------------------------------------------------------- /flightcode/python/led_nop.py: -------------------------------------------------------------------------------- 1 | 2 | def blink(on_ms, off_ms): 3 | pass 4 | 5 | def off(): 6 | pass 7 | -------------------------------------------------------------------------------- /flightcode/python/led_solo.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def blink(on_ms, off_ms): 4 | os.system("echo timer > /sys/class/leds/user2/trigger") 5 | os.system("echo %d > /sys/class/leds/user2/delay_on" % (on_ms, )) 6 | os.system("echo %d > /sys/class/leds/user2/delay_off" % (off_ms, )) 7 | 8 | def off(): 9 | os.system("echo none > /sys/class/leds/user2/trigger") 10 | -------------------------------------------------------------------------------- /flightcode/python/rc_lock.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import errno 4 | import os 5 | 6 | 7 | # must match RcLock.cpp 8 | ro_lockfile = "/mnt/rootfs.ro/etc/.rc_lock" 9 | tmp_lockfile = "/tmp/.rc_lock" 10 | tmp_unlockfile = "/tmp/.rc_unlock" 11 | 12 | 13 | def locked(): 14 | if os.path.isfile(tmp_unlockfile): 15 | return False 16 | elif os.path.isfile(tmp_lockfile) or \ 17 | os.path.isfile(ro_lockfile): 18 | return True 19 | else: 20 | return False 21 | 22 | 23 | def lock_version(): 24 | with open(tmp_lockfile, 'a'): # "touch" 25 | os.utime(tmp_lockfile, None) 26 | 27 | 28 | def unlock_version(): 29 | try: 30 | os.unlink(tmp_lockfile) 31 | except OSError as e: 32 | if e.errno != errno.ENOENT: 33 | raise e 34 | 35 | 36 | def unlock_override(): 37 | with open(tmp_unlockfile, 'a'): # "touch" 38 | os.utime(tmp_unlockfile, None) 39 | -------------------------------------------------------------------------------- /flightcode/python/runStickCal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #Comment out the RCTX line in /etc/inittab 4 | sed -i 's/^RCTX.*/#&/g' /etc/inittab 5 | 6 | #stop the stm32 process 7 | init q 8 | sleep 1 9 | 10 | #update artoo 11 | echo "Press Ctrl+C to write the calibration" 12 | stick-cal.py /dev/ttymxc1 13 | 14 | #Uncomment the RCTX line 15 | sed -i 's/.\(RCTX*.\)/\1/g' /etc/inittab 16 | 17 | #start the stm32 process back up 18 | init q 19 | -------------------------------------------------------------------------------- /flightcode/python/slip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | class SlipDevice: 4 | 5 | END = chr(0300) # indicates end of packet 6 | ESC = chr(0333) # indicates byte stuffing 7 | ESC_END = chr(0334) # ESC ESC_END means END data byte 8 | ESC_ESC = chr(0335) # ESC ESC_ESC means ESC data byte 9 | 10 | def __init__(self, serial_dev): 11 | self.ser = serial_dev 12 | self.insync = False 13 | 14 | def sync(self): 15 | attempts = 0 16 | while 1: 17 | dat = self.ser.read() 18 | if not dat: 19 | attempts += 1 20 | if(attempts >= 3): 21 | print "slip sync read fail, breaking" 22 | return False 23 | continue 24 | 25 | if dat == self.END: 26 | self.insync = True 27 | return True 28 | 29 | def read(self): 30 | """ 31 | read a SLIP packet from artoo. 32 | """ 33 | pkt = [] 34 | 35 | if not self.insync: 36 | if(self.sync() == False): 37 | return pkt; 38 | 39 | while True: 40 | b = self.ser.read() 41 | if b == self.END: 42 | if len(pkt) > 0: 43 | return pkt 44 | elif b == self.ESC: 45 | b = self.ser.read() 46 | if b == self.ESC_END: 47 | pkt.append(self.END) 48 | elif b == self.ESC_ESC: 49 | pkt.append(self.ESC) 50 | else: 51 | pkt.append(b) 52 | else: 53 | pkt.append(b) 54 | 55 | def write(self, pkt): 56 | """ 57 | write a SLIP message to artoo 58 | """ 59 | 60 | slip_bytes = [self.END] 61 | for b in pkt: 62 | if b == self.END: 63 | slip_bytes.append(self.ESC) 64 | slip_bytes.append(self.ESC_END) 65 | elif b == self.ESC: 66 | slip_bytes.append(self.ESC) 67 | slip_bytes.append(self.ESC_ESC) 68 | else: 69 | slip_bytes.append(b) 70 | 71 | slip_bytes.append(self.END) 72 | self.ser.write("".join(slip_bytes)) 73 | -------------------------------------------------------------------------------- /flightcode/python/stm32_defs.py: -------------------------------------------------------------------------------- 1 | # Packet IDs. These must match "enum MsgID" in artoo/src/hostprotocol.h. 2 | PKT_ID_NOP = 0 3 | PKT_ID_DSM = 1 4 | PKT_ID_CAL = 2 5 | PKT_ID_SYSINFO = 3 6 | PKT_ID_MAVLINK = 4 7 | PKT_ID_SET_RAW_IO = 5 8 | PKT_ID_RAW_IO_REPORT = 6 9 | PKT_ID_PAIR_REQUEST = 7 10 | PKT_ID_PAIR_CONFIRM = 8 11 | PKT_ID_PAIR_RESULT = 9 12 | PKT_ID_SHUTDOWN_REQUEST = 10 13 | -------------------------------------------------------------------------------- /flightcode/python/usb_nop.py: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | def init(): 4 | pass 5 | 6 | def uninit(): 7 | pass 8 | 9 | def enable(): 10 | pass 11 | 12 | def disable(): 13 | pass 14 | -------------------------------------------------------------------------------- /flightcode/python/usb_solo.py: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | import gpio 4 | 5 | ENABLE_GPIO = 19 6 | SELECT_GPIO = 21 7 | 8 | def init(): 9 | gpio.export(SELECT_GPIO) 10 | gpio.export(ENABLE_GPIO) 11 | gpio.set_dir(SELECT_GPIO, "out") 12 | gpio.set_dir(ENABLE_GPIO, "out") 13 | gpio.set(SELECT_GPIO, 0) 14 | gpio.set(ENABLE_GPIO, 1) 15 | 16 | def uninit(): 17 | gpio.unexport(SELECT_GPIO) 18 | gpio.unexport(ENABLE_GPIO) 19 | 20 | def enable(): 21 | gpio.set(SELECT_GPIO, 1) # VBUS on 22 | gpio.set(ENABLE_GPIO, 0) # D+/D- connect 23 | 24 | def disable(): 25 | gpio.set(ENABLE_GPIO, 1) # D+/D- disconnect 26 | gpio.set(SELECT_GPIO, 0) # VBUS off 27 | -------------------------------------------------------------------------------- /flightcode/rssi/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util 13 | 14 | INCROOT = $(OECORE_TARGET_SYSROOT)/usr/include 15 | 16 | INCS = -I../util 17 | 18 | CXXFLAGS += -Wall -I$(INCROOT)/libnl3 $(INCS) 19 | 20 | LDLIBS += -lnl-3 -lnl-genl-3 21 | 22 | BIN = rssi_send 23 | 24 | all: $(BIN) 25 | 26 | $(BIN): rssi_send.o util.o 27 | $(LINK.cpp) -o $(BIN) rssi_send.o util.o $(LDLIBS) 28 | 29 | clean: 30 | $(RM) *.o *~ $(BIN) 31 | 32 | BASE := ../.. 33 | 34 | fmt: 35 | @python $(BASE)/tools/build/clang-format-run.py --apply 36 | 37 | fmt-diff: 38 | @python $(BASE)/tools/build/clang-format-run.py 39 | 40 | .PHONY: all clean fmt fmt-diff 41 | -------------------------------------------------------------------------------- /flightcode/stm32/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /flightcode/stm32/AppConnected.h: -------------------------------------------------------------------------------- 1 | #ifndef APP_CONNECTED_H 2 | #define APP_CONNECTED_H 3 | 4 | #include 5 | #include 6 | #include "packetTypes.h" 7 | #include "net_wmm.h" 8 | #include "PacketHandler.h" 9 | 10 | /*********************************************************************** 11 | Class: The AppConnected class. 12 | 13 | Description: Creates a UDP socket for app-connected message data. 14 | ***********************************************************************/ 15 | class AppConnected : public PacketHandler 16 | { 17 | public: 18 | // Constructor. Takes an IP address, port and TOS value 19 | AppConnected(string ipaddr, int port) 20 | : PacketHandler(ipaddr, port, IP_TOS_DEFAULT, PKT_ID_SOLO_APP_CONNECTION){}; 21 | }; 22 | 23 | #endif // APP_CONNECTED_H 24 | -------------------------------------------------------------------------------- /flightcode/stm32/ButtonEventHandler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "packetTypes.h" 3 | #include "util.h" 4 | #include "net_wmm.h" 5 | #include "TcpServer.h" 6 | #include "ButtonEventMessage.h" 7 | #include "ButtonEventHandler.h" 8 | 9 | using namespace std; 10 | 11 | // Constructor - create and start the server that allows clients to connect 12 | // and receive button events 13 | ButtonEventHandler::ButtonEventHandler(int port) 14 | : PacketHandler("127.0.0.1", port, 0x02, PKT_ID_BUTTON_EVENT), tcpServer(port, "ButtonEvent") 15 | { 16 | tcpServer.start(); 17 | } 18 | 19 | // upHandler - called when a button event message is received from the STM32. 20 | // Prepend the timestamp and send it to all attached clients (if any). 21 | // CLOCK_MONOTONIC is used because it seems more likely that a client would be 22 | // interested in intervals between button events instead of absolute button 23 | // event time. 24 | int ButtonEventHandler::upHandler(char serBuf[], int len) 25 | { 26 | uint64_t now_us; 27 | now_us = clock_gettime_us(CLOCK_MONOTONIC); 28 | ButtonEventMessage msg(now_us, serBuf); 29 | tcpServer.send_clients(&msg, sizeof(msg)); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /flightcode/stm32/ButtonEventHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef BUTTON_EVENT_HANDLER_H 2 | #define BUTTON_EVENT_HANDLER_H 3 | 4 | #include "PacketHandler.h" 5 | #include "TcpServer.h" 6 | 7 | /*********************************************************************** 8 | Class: The ButtonEventHandler class. 9 | 10 | Description: Button events are upstream-only. A TCP server is created; 11 | a client connected to the server gets all button events 12 | that arrive from the STM32. 13 | ***********************************************************************/ 14 | 15 | class ButtonEventHandler : public PacketHandler 16 | { 17 | 18 | public: 19 | ButtonEventHandler(int port); 20 | 21 | int upHandler(char serBuf[], int len); 22 | 23 | private: 24 | // clients attach to this to receive button events 25 | TcpServer tcpServer; 26 | }; 27 | 28 | #endif // BUTTON_EVENT_HANDLER_H 29 | -------------------------------------------------------------------------------- /flightcode/stm32/ButtonFunctionCfg.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "packetTypes.h" 4 | #include "ButtonFunctionCfg.h" 5 | 6 | // Output ButtonFunctionCfgMsg to a stream in a human-readable format 7 | ostream &operator<<(ostream &os, const struct ButtonFunctionCfgMsg &msg) 8 | { 9 | os << "button_id=" << int(msg.button_id); 10 | os << " button_event=" << int(msg.button_event); 11 | os << " shot_id=" << int(msg.shot_id); 12 | os << " state=" << int(msg.state); 13 | // is descriptor EOS-terminated? 14 | os << " descriptor=\"" << msg.descriptor << '\"'; 15 | return os; 16 | } 17 | 18 | // UDP port on local machine where downstream ButtonFunctionCfg should be sent 19 | unsigned ButtonFunctionCfg::udpPort = 0; 20 | 21 | ButtonFunctionCfg::ButtonFunctionCfg(int port) 22 | : PacketHandler("127.0.0.1", port, 0x02, PKT_ID_BUTTON_FUNCTION_CFG) 23 | { 24 | 25 | ButtonFunctionCfg::udpPort = port; 26 | 27 | } // ButtonFunctionCfg::ButtonFunctionCfg 28 | -------------------------------------------------------------------------------- /flightcode/stm32/ButtonFunctionCfg.h: -------------------------------------------------------------------------------- 1 | #ifndef BUTTON_FUNCTION_CFG_H 2 | #define BUTTON_FUNCTION_CFG_H 3 | 4 | #include 5 | #include 6 | #include "net_wmm.h" 7 | #include "PacketHandler.h" 8 | 9 | // Message as sent to the STM32; message from App is in SoloMessage.h 10 | struct __attribute((__packed__)) ButtonFunctionCfgMsg { 11 | // packet ID is prepended just before slip-encoding 12 | uint8_t button_id; 13 | uint8_t button_event; 14 | uint8_t shot_id; 15 | uint8_t state; 16 | char descriptor[0]; 17 | static const int descriptor_max = 20; // (does not appear in struct) 18 | }; 19 | 20 | static const int ButtonFunctionCfgMsg_BufSize = 21 | sizeof(ButtonFunctionCfgMsg) + ButtonFunctionCfgMsg::descriptor_max; 22 | 23 | ostream &operator<<(ostream &os, const struct ButtonFunctionCfgMsg &msg); 24 | 25 | /*********************************************************************** 26 | Class: The ButtonFunctionCfg class. 27 | 28 | Description: Creates a UDP socket for ButtonFunctionCfg data. 29 | ***********************************************************************/ 30 | class ButtonFunctionCfg : public PacketHandler 31 | { 32 | public: 33 | ButtonFunctionCfg(int port); 34 | 35 | // This is nasty, but I need a way to get the UDP port number to which 36 | // downstream messages should be sent from somewhere that does not have 37 | // access to the stm32's ButtonFunctionCfg object. This is set by the 38 | // constructor. 39 | static unsigned udpPort; 40 | }; 41 | 42 | #endif // BUTTON_FUNCTION_CFG_H 43 | -------------------------------------------------------------------------------- /flightcode/stm32/CircularBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "CircularBuffer.h" 4 | 5 | // Print CircularBuffer status to a stream (debug) 6 | std::ostream &operator<<(std::ostream &os, const CircularBuffer &c) 7 | { 8 | os << "size=" << c.size() << " used=" << c.used() << " free=" << c.free(); 9 | return os; 10 | } 11 | -------------------------------------------------------------------------------- /flightcode/stm32/ConfigStickAxes.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "packetTypes.h" 3 | #include "ConfigStickAxes.h" 4 | 5 | // UDP port on local machine where downstream ConfigStickAxesMsg should be sent 6 | unsigned ConfigStickAxes::udpPort = 0; 7 | 8 | ConfigStickAxes::ConfigStickAxes(int port) : PacketHandler("", port, 0x02, PKT_ID_CONFIG_STICK_AXES) 9 | { 10 | ConfigStickAxes::udpPort = port; 11 | } 12 | -------------------------------------------------------------------------------- /flightcode/stm32/ConfigStickAxes.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_STICK_AXES_H 2 | #define CONFIG_STICK_AXES_H 3 | 4 | #include "PacketHandler.h" 5 | 6 | class ConfigStickAxes : public PacketHandler 7 | { 8 | public: 9 | ConfigStickAxes(int port); 10 | 11 | static unsigned udpPort; 12 | }; 13 | 14 | #endif // CONFIG_STICK_AXES_H 15 | -------------------------------------------------------------------------------- /flightcode/stm32/ConfigSweepTime.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "packetTypes.h" 3 | #include "ConfigSweepTime.h" 4 | 5 | // UDP port on local machine where downstream ConfigSweepTime should be sent 6 | unsigned ConfigSweepTime::udpPort = 0; 7 | 8 | ConfigSweepTime::ConfigSweepTime(int port) : PacketHandler("", port, 0x02, PKT_ID_CONFIG_SWEEP_TIME) 9 | { 10 | ConfigSweepTime::udpPort = port; 11 | } 12 | -------------------------------------------------------------------------------- /flightcode/stm32/ConfigSweepTime.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_SWEEP_TIME_H 2 | #define CONFIG_SWEEP_TIME_H 3 | 4 | #include "PacketHandler.h" 5 | 6 | class ConfigSweepTime : public PacketHandler 7 | { 8 | public: 9 | ConfigSweepTime(int port); 10 | 11 | static unsigned udpPort; 12 | }; 13 | 14 | #endif // CONFIG_SWEEP_TIME_H 15 | -------------------------------------------------------------------------------- /flightcode/stm32/InputReport.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "packetTypes.h" 8 | #include "util.h" 9 | #include "net_wmm.h" 10 | #include "TcpServer.h" 11 | #include "InputReport.h" 12 | 13 | using namespace std; 14 | 15 | // Send an InputReport to a stream in a friendly format. 16 | ostream &operator<<(ostream &os, const struct InputReportMessage &msg) 17 | { 18 | os << "msgId=" << msg.msgId; 19 | os << " length=" << msg.length; 20 | os << " timestamp=" << msg.timestamp; 21 | os << " gimbalY=" << msg.gimbalY; 22 | os << " gimbalRate=" << msg.gimbalRate; 23 | os << " battery=" << msg.battery; 24 | return os; 25 | } 26 | 27 | // Constructor - create and start the server that allows clients to connect 28 | // and receive input reports 29 | InputReport::InputReport(int port, int msg_rate) 30 | : PacketHandler("127.0.0.1", port, IP_TOS_DEFAULT, PKT_ID_INPUT_REPORT), 31 | tcpServer(port, "InputReport"), msgInterval_us(1000000 / msg_rate), nextMsgTime_us(0) 32 | { 33 | tcpServer.start(); 34 | } 35 | 36 | // upHandler - called when an inpurt report message is received from the 37 | // STM32. Prepend the timestamp and send it to all attached clients (if any). 38 | // The timestamp is include in case it is useful for debug/analysis, and 39 | // CLOCK_MONOTONIC is used because it seems more likely that message intervals 40 | // are more interesting that absolute times. 41 | int InputReport::upHandler(char serBuf[], int len) 42 | { 43 | uint64_t now_us; 44 | now_us = clock_gettime_us(CLOCK_MONOTONIC); 45 | if (now_us > nextMsgTime_us) { 46 | InputReportMessage msg(now_us, serBuf); 47 | tcpServer.send_clients(&msg, sizeof(msg)); 48 | // the following assumes CLOCK_MONOTONIC (no jumps) 49 | if (nextMsgTime_us == 0) 50 | nextMsgTime_us = now_us; 51 | nextMsgTime_us += msgInterval_us; 52 | } 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /flightcode/stm32/InputReport.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUT_REPORT_H 2 | #define INPUT_REPORT_H 3 | 4 | #include 5 | #include 6 | #include "PacketHandler.h" 7 | #include "TcpServer.h" 8 | 9 | // The message as sent to clients connected to the TCP server 10 | struct __attribute((__packed__)) InputReportMessage { 11 | // These fields are expected to be the only data and in this order. 12 | // The message constructor takes the raw message from the STM32 and picks 13 | // out fields to fill these in. 14 | uint32_t msgId; 15 | uint32_t length; // bytes following, i.e. 16 16 | uint64_t timestamp; 17 | uint16_t gimbalY; 18 | uint16_t gimbalRate; 19 | uint16_t battery; 20 | uint16_t spare; // to make it a multiple of 4 21 | 22 | static const uint32_t MSG_ID = 2003; // XXX move elsewhere 23 | 24 | InputReportMessage(uint64_t ts, const char *rawMsg) 25 | : msgId(MSG_ID), length(sizeof(InputReportMessage) - 8), timestamp(ts), spare(0) 26 | { 27 | // rawMsg is as produced in artoo's Inputs::producePacket() (without 28 | // the initial packet ID). All fields little endian. 29 | gimbalY = rawMsg[0] | ((uint16_t)(rawMsg[1]) << 8); 30 | gimbalRate = rawMsg[2] | ((uint16_t)(rawMsg[3]) << 8); 31 | battery = rawMsg[4] | ((uint16_t)(rawMsg[5]) << 8); 32 | } 33 | }; 34 | 35 | /*********************************************************************** 36 | Class: The InputReport class. 37 | 38 | Description: Input reports are upstream-only. A TCP server is created; 39 | a client connected to the server gets input reports that 40 | arrive from the STM32. The constructor's 'msg_rate' 41 | determines how many messages per second are forwarded. 42 | Messages come from the STM32 at 50 Hz, but for battery 43 | monitoring, the forwarding rate can be set much lower 44 | (e.g. 1 Hz). 45 | ***********************************************************************/ 46 | 47 | class InputReport : public PacketHandler 48 | { 49 | 50 | public: 51 | InputReport(int port, int msg_rate); 52 | 53 | int upHandler(char serBuf[], int len); 54 | 55 | private: 56 | // clients attach to this to receive input reports 57 | TcpServer tcpServer; 58 | 59 | // message rate limiting 60 | unsigned msgInterval_us; 61 | uint64_t nextMsgTime_us; 62 | }; 63 | 64 | #endif // INPUT_REPORT_H 65 | -------------------------------------------------------------------------------- /flightcode/stm32/LockoutState.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "packetTypes.h" 4 | #include "net_wmm.h" 5 | #include "LockoutState.h" 6 | 7 | // Output LockoutState to a stream in a human-readable format 8 | ostream &operator<<(ostream &os, const struct LockoutStateMsg &msg) 9 | { 10 | os << "lockout=" << (msg.lockout ? "true" : "false"); 11 | return os; 12 | } 13 | 14 | // UDP port on local machine where downstream LockoutState should be sent 15 | unsigned LockoutState::udpPort = 0; 16 | 17 | LockoutState::LockoutState(int port) : PacketHandler("127.0.0.1", port, 0x02, PKT_ID_LOCKOUT_STATE) 18 | { 19 | LockoutState::udpPort = port; 20 | } 21 | -------------------------------------------------------------------------------- /flightcode/stm32/LockoutState.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCKOUT_STATE_H 2 | #define LOCKOUT_STATE_H 3 | 4 | #include 5 | #include 6 | #include "PacketHandler.h" 7 | 8 | // Message as sent to the STM32 9 | struct __attribute((__packed__)) LockoutStateMsg { 10 | // packet ID is prepended just before slip-encoding 11 | uint8_t lockout; // nonzero for lockout, zero for not locked out 12 | }; 13 | 14 | ostream &operator<<(ostream &os, const struct LockoutStateMsg &msg); 15 | 16 | /*********************************************************************** 17 | Class: The LockoutState class. 18 | 19 | Description: Creates a UDP socket for LockoutState data. 20 | ***********************************************************************/ 21 | class LockoutState : public PacketHandler 22 | { 23 | public: 24 | LockoutState(int port); 25 | 26 | static unsigned udpPort; 27 | }; 28 | 29 | #endif // LOCKOUT_STATE_H 30 | -------------------------------------------------------------------------------- /flightcode/stm32/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util ../ini ../ini/cpp 13 | 14 | INCS = -I../util -I../ini -I../ini/cpp 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) 18 | 19 | LIBS = -lpthread 20 | 21 | SRCS_CPP = stm32.cpp 22 | SRCS_CPP += PacketHandler.cpp 23 | SRCS_CPP += PairReq.cpp 24 | SRCS_CPP += RC.cpp 25 | SRCS_CPP += SLIP.cpp 26 | SRCS_CPP += SysInfo.cpp 27 | SRCS_CPP += Telem.cpp 28 | SRCS_CPP += ButtonEventMessage.cpp 29 | SRCS_CPP += ButtonEventHandler.cpp 30 | SRCS_CPP += InputReport.cpp 31 | SRCS_CPP += ButtonFunctionCfg.cpp 32 | SRCS_CPP += SetShotInfo.cpp 33 | SRCS_CPP += TcpServer.cpp 34 | SRCS_CPP += SoloMessage.cpp 35 | SRCS_CPP += INIReader.cpp 36 | SRCS_CPP += SerialLog.cpp 37 | SRCS_CPP += CircularBuffer.cpp 38 | SRCS_CPP += LockoutState.cpp 39 | SRCS_CPP += ConfigStickAxes.cpp 40 | SRCS_CPP += SetTelemUnits.cpp 41 | SRCS_CPP += ConfigSweepTime.cpp 42 | SRCS_C = ini.c 43 | SRCS_C += util.c 44 | SRCS_C += mutex.c 45 | SRCS_C += syslog.c 46 | 47 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 48 | 49 | MAIN = stm32 50 | 51 | all: $(MAIN) 52 | 53 | $(MAIN): $(OBJS) 54 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 55 | 56 | # This has run on a Linux host 57 | CircularBufferTest: CircularBufferTest.o CircularBuffer.o 58 | $(LINK.cpp) -o CircularBufferTest CircularBufferTest.o CircularBuffer.o 59 | 60 | # This has run on a Linux host 61 | SerialLogTest: SerialLogTest.o SerialLog.o CircularBuffer.o util.o 62 | $(LINK.cpp) -o SerialLogTest SerialLogTest.o SerialLog.o CircularBuffer.o util.o 63 | 64 | clean: 65 | $(RM) *.o *~ $(MAIN) *Test 66 | 67 | BASE := ../.. 68 | 69 | fmt: 70 | @python $(BASE)/tools/build/clang-format-run.py --apply 71 | 72 | fmt-diff: 73 | @python $(BASE)/tools/build/clang-format-run.py 74 | 75 | .PHONY: all clean fmt fmt-diff 76 | -------------------------------------------------------------------------------- /flightcode/stm32/PacketHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef _PACKETHANDLER_H_ 2 | #define _PACKETHANDLER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | /*********************************************************************** 11 | Class: The PacketHandler class. 12 | 13 | Description: Creates a UDP socket for data, which is sent 14 | bidirectionally to and from the stm32. This is the base 15 | class for all types of data handled by the stm32 16 | ***********************************************************************/ 17 | 18 | class PacketHandler 19 | { 20 | protected: 21 | // Socket descriptor and the socket address 22 | int _sock_fd; 23 | struct sockaddr_in _sock; 24 | int _pktID; 25 | 26 | public: 27 | // Constructor. Takes an IP address, port, TOS value 28 | // and the packet id int 29 | PacketHandler(string ipaddr, int port, int tos, int pktID); 30 | 31 | // Handles upstream data transmission, returns the number of bytes sent 32 | int upHandler(char serBuf[], int len); 33 | 34 | // Handles downstream data transmission 35 | void downHandler(int ser_fd, uint32_t debug = 0); 36 | 37 | // The upstream thread needs to get the file descriptor 38 | inline int getfd(void) 39 | { 40 | return _sock_fd; 41 | }; 42 | }; 43 | 44 | #endif //_PACKETHANDLER_H 45 | -------------------------------------------------------------------------------- /flightcode/stm32/PairReq.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "PairReq.h" 6 | 7 | using namespace std; 8 | 9 | // This is really a pair confirm message and should be a separate handler from 10 | // pair request (down is pair request, up is pair confirm, but with different 11 | // packet IDs). 12 | 13 | int PairReq::upHandler(char serBuf[], int len) 14 | { 15 | int nBytes; 16 | 17 | syslog(LOG_INFO, "pair confirm going up for \"%s\"", serBuf); 18 | 19 | nBytes = strlen(serBuf) + 1; 20 | 21 | nBytes = sendto(_sock_fd, serBuf, nBytes, 0, (struct sockaddr *)&_sock, sizeof(_sock)); 22 | 23 | if (nBytes == -1) { 24 | syslog(LOG_ERR, "PairReq: sendto failed"); 25 | nBytes = 0; 26 | } 27 | 28 | return nBytes; 29 | } 30 | -------------------------------------------------------------------------------- /flightcode/stm32/PairReq.h: -------------------------------------------------------------------------------- 1 | #ifndef _PAIRREQ_H_ 2 | #define _PAIRREQ_H_ 3 | 4 | #include 5 | #include "packetTypes.h" 6 | #include "net_wmm.h" 7 | #include "PacketHandler.h" 8 | 9 | using namespace std; 10 | 11 | /*********************************************************************** 12 | Class: The pairReq class. 13 | 14 | Description: Creates a UDP socket for pairReqest data. 15 | ***********************************************************************/ 16 | class PairReq : public PacketHandler 17 | { 18 | public: 19 | // Constructor. Takes an IP address, port and TOS value 20 | PairReq(string ipaddr, int port) : PacketHandler(ipaddr, port, 0x02, PKT_ID_PAIR_REQUEST){}; 21 | 22 | // Handles upstream data transmission 23 | int upHandler(char serBuf[], int len); 24 | }; 25 | 26 | #endif //_PAIRREQ_H 27 | -------------------------------------------------------------------------------- /flightcode/stm32/PairRes.h: -------------------------------------------------------------------------------- 1 | #ifndef _PAIRRES_H_ 2 | #define _PAIRRES_H_ 3 | 4 | #include 5 | #include "packetTypes.h" 6 | #include "net_wmm.h" 7 | #include "PacketHandler.h" 8 | 9 | using namespace std; 10 | 11 | /*********************************************************************** 12 | Class: The PairRes class. 13 | 14 | Description: Creates a UDP socket for pairRes data. 15 | ***********************************************************************/ 16 | class PairRes : public PacketHandler 17 | { 18 | public: 19 | // Constructor. Takes an IP address, port and TOS value 20 | PairRes(string ipaddr, int port) : PacketHandler(ipaddr, port, 0x02, PKT_ID_PAIR_RESULT){}; 21 | }; 22 | 23 | #endif //_PAIRRES_H 24 | -------------------------------------------------------------------------------- /flightcode/stm32/ParamStoredVals.h: -------------------------------------------------------------------------------- 1 | #ifndef PARAM_STORED_VALS_H 2 | #define PARAM_STORED_VALS_H 3 | 4 | #include "PacketHandler.h" 5 | #include "packetTypes.h" 6 | 7 | class ParamStoredVals : public PacketHandler 8 | { 9 | public: 10 | ParamStoredVals(int port) : PacketHandler("", port, 0x02, PKT_ID_PARAM_STORED_VALS){}; 11 | }; 12 | 13 | #endif // PARAM_STORED_VALS_H 14 | -------------------------------------------------------------------------------- /flightcode/stm32/RC.h: -------------------------------------------------------------------------------- 1 | #ifndef _RC_H_ 2 | #define _RC_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "PacketHandler.h" 8 | 9 | using namespace std; 10 | 11 | /*********************************************************************** 12 | Class: The RC class. 13 | 14 | Description: The RC class. Creates a UDP socket for RC channel 15 | transmission and handles all channel data encoding. 16 | ***********************************************************************/ 17 | 18 | class RC : public PacketHandler 19 | { 20 | private: 21 | // Packs the channel data from the STM32 with a timestamp 22 | // and sequence which is sent to the receiver on the Solo. 23 | int constructMessage(char inBuf[], char outBuf[], int inBufLen); 24 | 25 | // RC packet information 26 | int32_t _sequence; 27 | 28 | // If we're connected to the Solo yet. 29 | bool _connected; 30 | 31 | public: 32 | // Constructor. Takes an IP address, port and TOS value 33 | RC(string ipaddr, int port, int tos); 34 | 35 | // Override the uphandler 36 | int upHandler(char serBuf[], int len); 37 | 38 | // If we've got a new Solo IP address 39 | void setSoloIP(string *address); 40 | }; 41 | 42 | #endif //_RC_H 43 | -------------------------------------------------------------------------------- /flightcode/stm32/SLIP.h: -------------------------------------------------------------------------------- 1 | #ifndef _SLIP_H 2 | #define _SLIP_H 3 | 4 | class SLIP 5 | { 6 | public: 7 | SLIP(char *msg, int maxMsgLen); 8 | 9 | protected: 10 | char *_msg; // Pointer to the message bufer 11 | char *_msgPtr; // The current read/write pointer 12 | int _maxLen; 13 | int _msgLen; 14 | bool _escTriggered; 15 | static const unsigned END = 0300; // indicates end of packet 16 | static const unsigned ESC = 0333; // indicates byte stuffing 17 | static const unsigned ESC_END = 0334; // ESC ESC_END means END data byte 18 | static const unsigned ESC_ESC = 0335; // ESC ESC_ESC means ESC data byte 19 | 20 | void reset(void) 21 | { 22 | _msgPtr = _msg; 23 | _msgLen = 0; 24 | _escTriggered = false; 25 | }; 26 | }; 27 | 28 | class SLIPDecoder : public SLIP 29 | { 30 | public: 31 | SLIPDecoder(char *msg, int maxMsgLen); 32 | int addByte(char *b); // Returns -1: error, 0:no message yet, >0:done, msg available 33 | }; 34 | 35 | class SLIPEncoder : public SLIP 36 | { 37 | public: 38 | SLIPEncoder(char *msg, int maxMsgLen); 39 | int encode(char *buf, int bufLen); // Encodes an array of bytes, returns len 40 | }; 41 | 42 | #endif //_SLIP_H 43 | -------------------------------------------------------------------------------- /flightcode/stm32/SerialLogTest.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "SerialLog.h" 5 | 6 | using namespace std; 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | static const unsigned log_size = 100; 11 | SerialLog sl(log_size); 12 | const char *s; 13 | bool b; 14 | static const unsigned num_pkts = 1000; 15 | unsigned n[num_pkts]; 16 | unsigned pkt_num_oldest = 0; 17 | unsigned total = 0; 18 | unsigned pkt_num; 19 | const char *pkts[10] = {"", "1", "12", "123", "1234", 20 | "12345", "123456", "1234567", "12345678", "123456789"}; 21 | uint8_t f; 22 | const uint8_t flags[2] = {SerialLog::PKTFLG_UP, SerialLog::PKTFLG_DOWN}; 23 | 24 | cout << sl << endl; 25 | 26 | for (pkt_num = 0; pkt_num < num_pkts; pkt_num++) { 27 | s = pkts[pkt_num % 10]; 28 | f = flags[pkt_num % 2]; 29 | cout << "log_packet \"" << s << "\"..."; 30 | b = sl.log_packet(s, strlen(s), f); 31 | n[pkt_num] = sizeof(SerialLog::PacketEntry) + strlen(s); 32 | total += n[pkt_num]; 33 | while (total >= log_size) 34 | total -= n[pkt_num_oldest++]; 35 | if (b && sl.used() == total && sl.free() == sl.size() - total - 1) 36 | cout << "OK" << endl; 37 | else 38 | cout << "ERROR" << endl; 39 | } 40 | 41 | cout << sl << endl; 42 | 43 | return 0; 44 | 45 | } // main 46 | -------------------------------------------------------------------------------- /flightcode/stm32/SetShotInfo.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "packetTypes.h" 4 | #include "net_wmm.h" 5 | #include "SetShotInfo.h" 6 | 7 | // Output SetShotInfoMsg to a stream in a human-readable format 8 | ostream &operator<<(ostream &os, const struct SetShotInfoMsg &msg) 9 | { 10 | os << "descriptor=\"" << msg.descriptor << '\"'; // assume EOS-terminated 11 | return os; 12 | } 13 | 14 | // UDP port on local machine where downstream SetShotInfo should be sent 15 | unsigned SetShotInfo::udpPort = 0; 16 | 17 | SetShotInfo::SetShotInfo(int port) : PacketHandler("127.0.0.1", port, 0x02, PKT_ID_SET_SHOT_INFO) 18 | { 19 | 20 | SetShotInfo::udpPort = port; 21 | 22 | } // SetShotInfo::SetShotInfo 23 | -------------------------------------------------------------------------------- /flightcode/stm32/SetShotInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef SET_SHOT_INFO_H 2 | #define SET_SHOT_INFO_H 3 | 4 | #include 5 | #include 6 | #include "PacketHandler.h" 7 | 8 | // Message as sent to the STM32; message from App is in SoloMessage.h 9 | struct __attribute((__packed__)) SetShotInfoMsg { 10 | // packet ID is prepended just before slip-encoding 11 | char descriptor[0]; 12 | static const int descriptor_max = 64; // (does not appear in struct) 13 | }; 14 | 15 | static const int SetShotInfoMsg_BufSize = sizeof(SetShotInfoMsg) + SetShotInfoMsg::descriptor_max; 16 | 17 | ostream &operator<<(ostream &os, const struct SetShotInfoMsg &msg); 18 | 19 | /*********************************************************************** 20 | Class: The SetShotInfo class. 21 | 22 | Description: Creates a UDP socket for SetShotInfo data. 23 | ***********************************************************************/ 24 | class SetShotInfo : public PacketHandler 25 | { 26 | public: 27 | SetShotInfo(int port); 28 | 29 | // This is nasty, but I need a way to get the UDP port number to which 30 | // downstream messages should be sent from somewhere that does not have 31 | // access to the stm32's setShotInfo object. This is set by the 32 | // constructor. 33 | static unsigned udpPort; 34 | }; 35 | 36 | #endif // SET_SHOT_INFO_H 37 | -------------------------------------------------------------------------------- /flightcode/stm32/SetTelemUnits.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "packetTypes.h" 3 | #include "SetTelemUnits.h" 4 | 5 | // UDP port on local machine where downstream SetTelemUnits should be sent 6 | unsigned SetTelemUnits::udpPort = 0; 7 | 8 | SetTelemUnits::SetTelemUnits(int port) : PacketHandler("", port, 0x02, PKT_ID_SET_TELEM_UNITS) 9 | { 10 | SetTelemUnits::udpPort = port; 11 | } 12 | 13 | void SetTelemUnits::set(string &setting) 14 | { 15 | char buf = 1; // default is metric 16 | 17 | if (setting == "imperial") 18 | buf = 0; 19 | 20 | sendto(_sock_fd, &buf, 1, 0, (struct sockaddr *)&_sock, sizeof(_sock)); 21 | } 22 | -------------------------------------------------------------------------------- /flightcode/stm32/SetTelemUnits.h: -------------------------------------------------------------------------------- 1 | #ifndef SET_TELEM_UNITS_H 2 | #define SET_TELEM_UNITS_H 3 | 4 | #include "PacketHandler.h" 5 | 6 | class SetTelemUnits : public PacketHandler 7 | { 8 | public: 9 | SetTelemUnits(int port); 10 | 11 | void set(string &setting); 12 | 13 | static unsigned udpPort; 14 | }; 15 | 16 | #endif // SET_TELEM_UNITS_H 17 | -------------------------------------------------------------------------------- /flightcode/stm32/SoloMessage.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "SoloMessage.h" 5 | 6 | using namespace std; 7 | 8 | // instantiate one of these to see debug output at startup 9 | // SoloMessage::Tester tester; 10 | 11 | SoloMessage::Tester::Tester(void) 12 | { 13 | cout << "SoloMessage::Hdr: " << sizeof(Hdr) << " bytes" << endl; 14 | cout << "SoloMessage::SetButtonString: " << sizeof(SetButtonString) << " bytes" << endl; 15 | cout << "SoloMessage::SetShotString: " << sizeof(SetShotString) << " bytes" << endl; 16 | } 17 | 18 | // Print SoloMessage::Hdr in a human-readable format 19 | ostream &operator<<(ostream &os, const struct SoloMessage::Hdr &msg) 20 | { 21 | os << "type=" << msg.type; 22 | os << " length=" << msg.length; 23 | const uint8_t *p = (const uint8_t *)&msg + sizeof(msg); 24 | os << setfill('0') << hex; 25 | for (unsigned i = 0; i < msg.length; i++) 26 | os << ' ' << setw(2) << int(p[i]); 27 | os << setfill(' ') << dec; 28 | return os; 29 | } 30 | 31 | // Print SoloMessage::SetButtonString in a human-readable format 32 | ostream &operator<<(ostream &os, const struct SoloMessage::SetButtonString &msg) 33 | { 34 | os << "type=" << msg.type; 35 | os << " length=" << msg.length; 36 | os << " button_id=" << msg.button_id; 37 | os << " button_event=" << msg.button_event; 38 | os << " shot_id=" << msg.shot_id; 39 | os << " state=" << msg.state; 40 | os << " descriptor=\"" << msg.descriptor << '\"'; // assume EOS-terminated 41 | return os; 42 | } 43 | 44 | // Print SoloMessage::SetShotString in a human-readable format 45 | ostream &operator<<(ostream &os, const struct SoloMessage::SetShotString &msg) 46 | { 47 | os << "type=" << msg.type; 48 | os << " length=" << msg.length; 49 | os << " descriptor=\"" << msg.descriptor << '\"'; // assume EOS-terminated 50 | return os; 51 | } 52 | -------------------------------------------------------------------------------- /flightcode/stm32/SoloMessage.h: -------------------------------------------------------------------------------- 1 | #ifndef SOLO_MESSAGE_H 2 | #define SOLO_MESSAGE_H 3 | 4 | #include 5 | #include 6 | 7 | // Messages to/from App or ShotMgr 8 | 9 | namespace SoloMessage 10 | { 11 | 12 | struct Hdr { 13 | uint32_t type; 14 | uint32_t length; // bytes following this header 15 | 16 | // type field: 17 | // MUST MATCH: SoloLink/app/shots/app_packet.py 18 | // MUST MATCH: iSolo/networking/SoloPacket.swift 19 | static const uint32_t GET_CURRENT_SHOT = 0; 20 | static const uint32_t SET_CURRENT_SHOT = 1; 21 | static const uint32_t LOCATION = 2; 22 | static const uint32_t RECORD_POSITION = 3; 23 | static const uint32_t CABLE_CAM_OPTIONS = 4; 24 | // MUST MATCH: SoloLink/flightcode/stm32/btn_msg.py 25 | static const uint32_t BUTTON_EVENT = 2000; 26 | static const uint32_t SET_BUTTON_STRING = 2001; 27 | static const uint32_t SET_SHOT_STRING = 2002; 28 | }; 29 | 30 | struct SetButtonString : public Hdr { 31 | uint8_t button_id; 32 | uint8_t button_event; 33 | uint8_t shot_id; 34 | uint8_t state; 35 | char descriptor[0]; 36 | }; 37 | 38 | struct SetShotString : public Hdr { 39 | char descriptor[0]; 40 | }; 41 | 42 | struct Tester { 43 | Tester(void); 44 | }; 45 | 46 | }; // namespace SoloMessage 47 | 48 | std::ostream &operator<<(std::ostream &os, const struct SoloMessage::Hdr &msg); 49 | 50 | std::ostream &operator<<(std::ostream &os, const struct SoloMessage::SetButtonString &msg); 51 | 52 | std::ostream &operator<<(std::ostream &os, const struct SoloMessage::SetShotString &msg); 53 | 54 | #endif // SOLO_MESSAGE_H 55 | -------------------------------------------------------------------------------- /flightcode/stm32/SysInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYSINFO_H_ 2 | #define _SYSINFO_H_ 3 | 4 | #include 5 | #include "PacketHandler.h" 6 | #include "packetTypes.h" 7 | #include "net_wmm.h" 8 | 9 | using namespace std; 10 | 11 | /*********************************************************************** 12 | Class: The sysinfo class. 13 | 14 | Description: Creates a UDP socket for system info. 15 | ***********************************************************************/ 16 | 17 | class SysInfo : public PacketHandler 18 | { 19 | public: 20 | // Constructor. Takes an IP address and port 21 | SysInfo(string ipaddr, int port) : PacketHandler(ipaddr, port, 0x03, PKT_ID_SYS_INFO){}; 22 | 23 | // Overriden upHandler to read STM32 board data 24 | int upHandler(char serBuf[], int len); 25 | 26 | // Send a blank packet to the sysinfo port to "ping" the STM32 27 | void ping(void); 28 | }; 29 | 30 | #endif //_SYSINFO_H 31 | -------------------------------------------------------------------------------- /flightcode/stm32/Telem.h: -------------------------------------------------------------------------------- 1 | #ifndef _TELEM_H_ 2 | #define _TELEM_H_ 3 | 4 | #include 5 | #include 6 | #include "link_packet.h" 7 | #include "PacketHandler.h" 8 | 9 | /*********************************************************************** 10 | Class: The telem class. 11 | 12 | Description: Creates a UDP socket for telemetry data, which is sent 13 | bidirectionally to and from the stm32. 14 | ***********************************************************************/ 15 | 16 | class Telem : public PacketHandler 17 | { 18 | public: 19 | // Constructor. Takes an IP address and port 20 | Telem(string ipaddr, int port, unsigned log_gaps_us, unsigned pkt_delay_max, 21 | string &pkt_delay_filename); 22 | 23 | // Special downhandler that checks mavlink types 24 | void downHandler(int ser_fd, int verbosity = 0); 25 | 26 | private: 27 | void pkt_delay_open(void); 28 | void pkt_delay_write(LinkPacket &packet); 29 | unsigned _log_gap_us; 30 | unsigned _log_delay_max; 31 | string _log_delay_filename; 32 | FILE *_fp_delay; 33 | unsigned _delay_cnt; 34 | }; 35 | 36 | #endif //_TELEM_H 37 | -------------------------------------------------------------------------------- /flightcode/stm32/Updater.h: -------------------------------------------------------------------------------- 1 | #ifndef UPDATER_H 2 | #define UPDATER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "packetTypes.h" 9 | #include "net_wmm.h" 10 | #include "PacketHandler.h" 11 | 12 | using namespace std; 13 | 14 | /*********************************************************************** 15 | Class: The Updater class. 16 | 17 | Description: Creates a UDP socket for updater message data. 18 | ***********************************************************************/ 19 | class Updater : public PacketHandler 20 | { 21 | public: 22 | // Constructor. Takes an IP address, port and TOS value 23 | Updater(string ipaddr, int port) : PacketHandler(ipaddr, port, 0x02, PKT_ID_UPDATER){}; 24 | }; 25 | 26 | #endif // UPDATER_H 27 | -------------------------------------------------------------------------------- /flightcode/stm32/app_connected_msg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Send "app connected" message 4 | # Required artoo 0.7.9 or later. 5 | 6 | import socket 7 | import struct 8 | import sys 9 | 10 | DISCONNECTED = 0 11 | CONNECTED = 1 12 | 13 | # Must match flightcode/stm32 14 | APP_CONNECTED_PORT = 5026 15 | 16 | def send(app_connected): 17 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 18 | msg = struct.pack("!B", app_connected) 19 | s.sendto(msg, ("127.0.0.1", APP_CONNECTED_PORT)) 20 | s.close() 21 | 22 | def send_connected(): 23 | send(CONNECTED) 24 | 25 | def send_disconnected(): 26 | send(DISCONNECTED) 27 | 28 | def usage(): 29 | print "usage: app_connected.py " 30 | print " where is one of" 31 | print " c[onnected] tell stm32 app is connected" 32 | print " d[isconnected] tell stm32 app is disconnected" 33 | 34 | if __name__ == "__main__": 35 | # one required argument: "c[onnected]" or "d[isconnected]" 36 | if len(sys.argv) != 2: 37 | usage() 38 | elif sys.argv[1][0] == "c": 39 | send_connected() 40 | elif sys.argv[1][0] == "d": 41 | send_disconnected() 42 | else: 43 | usage() 44 | -------------------------------------------------------------------------------- /flightcode/stm32/btn_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import socket 4 | import struct 5 | import threading 6 | from sololink import btn_msg 7 | 8 | HOST = "10.1.1.1" 9 | PORT = 5016 10 | 11 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 12 | print "connecting to", HOST, ":", PORT, "...", 13 | s.connect((HOST, PORT)) 14 | print "OK" 15 | 16 | def in_thread(s): 17 | while True: 18 | msg = btn_msg.recv(s) 19 | if msg is None: 20 | print "received \"None\"" 21 | break 22 | elif len(msg) != 4: 23 | print "received funky message: ", str(msg) 24 | else: 25 | print "received:", msg[0], \ 26 | btn_msg.ButtonName[msg[1]], \ 27 | btn_msg.EventName[msg[2]], msg[3] 28 | if btn_msg.msg_buf_long != 0: 29 | print "btn_msg.msg_buf_long=%d!" % btn_msg.msg_buf_long 30 | btn_msg.msg_buf_long = 0 31 | if btn_msg.msg_buf_short != 0: 32 | print "btn_msg.msg_buf_short=%d!" % btn_msg.msg_buf_short 33 | btn_msg.msg_buf_short = 0 34 | 35 | in_id = threading.Thread(target=in_thread, args=(s,)) 36 | in_id.daemon = True 37 | in_id.start() 38 | 39 | format = 1 40 | while True: 41 | 42 | desc = raw_input() 43 | 44 | # allow changing which message goes out 45 | if desc == "1": 46 | format = 1 47 | continue; 48 | elif desc == "2": 49 | format = 2 50 | continue; 51 | 52 | if format == 1: 53 | button_id = btn_msg.ButtonA 54 | shot_id = 0 55 | btn_msg.sendArtooString(s, button_id, shot_id, desc + "\0") 56 | elif format == 2: 57 | btn_msg.sendShotString(s, desc + "\0") 58 | -------------------------------------------------------------------------------- /flightcode/stm32/config_stick_axes_msg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import socket 4 | import struct 5 | 6 | # Must match flightcode/stm32 and/or config/sololink.orig 7 | CONFIG_STICK_AXES_PORT = 5010 8 | 9 | # Send message to STM32 via stm32 process 10 | # 11 | # Message is packed stick config data, but does not have the one-byte 12 | # packet ID at the start. 13 | def send(msg): 14 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 15 | s.sendto(msg, ("127.0.0.1", CONFIG_STICK_AXES_PORT)) 16 | s.close() 17 | 18 | def pack_stick(stick_id, direction, expo): 19 | return struct.pack(" " 13 | print " set sweep time settings" 14 | 15 | 16 | if __name__ == "__main__": 17 | 18 | verbose = False # True for debug 19 | 20 | pp = pprint.PrettyPrinter() 21 | 22 | # if two arguments, we are setting, and they are min and max 23 | if len(sys.argv) == 1: 24 | # getting 25 | min_sweep_s = None 26 | max_sweep_s = None 27 | elif len(sys.argv) == 3: 28 | # setting - arguments must be integers 29 | try: 30 | min_sweep_s = int(sys.argv[1]) 31 | max_sweep_s = int(sys.argv[2]) 32 | except: 33 | usage() 34 | sys.exit(1) 35 | 36 | if min_sweep_s is not None and max_sweep_s is not None: 37 | # create "config sweep time" message 38 | msg = config_sweep_time_msg.pack(min_sweep_s, max_sweep_s) 39 | 40 | # send message to stm32 41 | config_sweep_time_msg.send(msg) 42 | 43 | # retrieve parameters to verify 44 | params = param_stored_vals_msg.fetch() 45 | 46 | # params is a string; unpack to a dictionary 47 | params = param_stored_vals_msg.unpack(params) 48 | if verbose: 49 | print "params message:" 50 | pp.pprint(params) 51 | 52 | if min_sweep_s is not None and max_sweep_s is not None: 53 | # verify that sweep times are as requested 54 | if params['sweepConfigs'][0] != (min_sweep_s, max_sweep_s): 55 | print "requested sweep times (%d, %d); not returned in params" % \ 56 | (min_sweep_s, max_sweep_s) 57 | print "returned params:" 58 | pp.pprint(params['sweepConfigs']) 59 | sys.exit(1) 60 | 61 | print "%d %d" % (params['sweepConfigs'][0][0], params['sweepConfigs'][0][1]) 62 | 63 | sys.exit(0) 64 | -------------------------------------------------------------------------------- /flightcode/stm32/config_sweep_time_msg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import socket 4 | import struct 5 | 6 | # Must match flightcode/stm32 and/or config/sololink.orig 7 | CONFIG_SWEEP_TIME_PORT = 5022 8 | 9 | # Send message to STM32 via stm32 process 10 | # 11 | # Message is packed sweep time data, but does not have the one-byte 12 | # packet ID at the start. 13 | def send(msg): 14 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 15 | s.sendto(msg, ("127.0.0.1", CONFIG_SWEEP_TIME_PORT)) 16 | s.close() 17 | 18 | def pack(min_sweep_s, max_sweep_s): 19 | return struct.pack(" next_print_time: 35 | print "received:", str(msg) 36 | next_print_time += print_interval 37 | 38 | if input_report_msg.msg_buf_long != 0: 39 | print "input_report_msg.msg_buf_long=%d!" % input_report_msg.msg_buf_long 40 | input_report_msg.msg_buf_long = 0 41 | 42 | if input_report_msg.msg_buf_short != 0: 43 | print "input_report_msg.msg_buf_short=%d!" % input_report_msg.msg_buf_short 44 | input_report_msg.msg_buf_short = 0 45 | -------------------------------------------------------------------------------- /flightcode/stm32/lockout_msg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Show/hide "update required" screen. 4 | # Required artoo 0.7.0 or later. 5 | 6 | import socket 7 | import struct 8 | import sys 9 | 10 | UNLOCK = 0 11 | LOCK = 1 12 | 13 | # Must match flightcode/stm32 14 | LOCKOUT_STATE_PORT = 5020 15 | 16 | def send(lock_state): 17 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 18 | msg = struct.pack("!B", lock_state) 19 | s.sendto(msg, ("127.0.0.1", LOCKOUT_STATE_PORT)) 20 | s.close() 21 | 22 | def send_lock(): 23 | send(LOCK) 24 | 25 | def send_unlock(): 26 | send(UNLOCK) 27 | 28 | def usage(): 29 | print "usage: lockout_msg.py " 30 | print " where is one of" 31 | print " lock show \"update required\" screen" 32 | print " unlock hide \"update required\" screen" 33 | 34 | if __name__ == "__main__": 35 | # one required argument: "lock" or "unlock" 36 | if len(sys.argv) != 2: 37 | usage() 38 | elif sys.argv[1] == "lock": 39 | send_lock() 40 | elif sys.argv[1] == "unlock": 41 | send_unlock() 42 | else: 43 | usage() 44 | -------------------------------------------------------------------------------- /flightcode/stm32/packetTypes.h: -------------------------------------------------------------------------------- 1 | #ifndef _PACKETTYPES_H 2 | #define _PACKETTYPES_H 3 | 4 | /*********************************************************************** 5 | Serial packet IDs 6 | Match constants in artoo/src/hostProtocol.h 7 | ***********************************************************************/ 8 | #define PKT_ID_NOP 0 9 | #define PKT_ID_DSM_CHANNELS 1 10 | #define PKT_ID_CALIBRATE 2 11 | #define PKT_ID_SYS_INFO 3 12 | #define PKT_ID_MAVLINK 4 13 | #define PKT_ID_SET_RAW_IO 5 14 | #define PKT_ID_RAW_IO_REPORT 6 15 | #define PKT_ID_PAIR_REQUEST 7 16 | #define PKT_ID_PAIR_CONFIRM 8 17 | #define PKT_ID_PAIR_RESULT 9 18 | #define PKT_ID_SHUTDOWN_REQUEST 10 19 | #define PKT_ID_PARAM_STORED_VALS 11 20 | #define PKT_ID_OUTPUT_TEST 12 21 | #define PKT_ID_BUTTON_EVENT 13 22 | #define PKT_ID_INPUT_REPORT 14 23 | #define PKT_ID_CONFIG_STICK_AXES 15 24 | #define PKT_ID_BUTTON_FUNCTION_CFG 16 25 | #define PKT_ID_SET_SHOT_INFO 17 26 | #define PKT_ID_UPDATER 18 27 | #define PKT_ID_LOCKOUT_STATE 19 28 | #define PKT_ID_SELF_TEST 20 // test fixture only 29 | #define PKT_ID_CONFIG_SWEEP_TIME 21 30 | #define PKT_ID_GPIO_TEST 22 31 | #define PKT_ID_TEST_EVENT 23 32 | #define PKT_ID_SET_TELEM_UNITS 24 33 | #define PKT_ID_INVALID_STICK_INPUTS 25 34 | #define PKT_ID_SOLO_APP_CONNECTION 26 35 | 36 | #define PKT_ID_MAX 27 37 | 38 | #endif //_PACKETTYPES_H 39 | -------------------------------------------------------------------------------- /flightcode/stm32/set_telem_units.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import set_telem_units_msg 5 | 6 | 7 | def usage(): 8 | print "usage: set_telem_units.py [metric|imperial]" 9 | 10 | 11 | if __name__ == "__main__": 12 | 13 | # one required argument: "metric" or "imperial" 14 | if len(sys.argv) != 2: 15 | usage() 16 | sys.exit(1) 17 | 18 | if sys.argv[1] == "metric": 19 | msg = set_telem_units_msg.pack_msg(True) 20 | elif sys.argv[1] == "imperial": 21 | msg = set_telem_units_msg.pack_msg(False) 22 | else: 23 | usage() 24 | sys.exit(1) 25 | 26 | # send message to stm32 27 | set_telem_units_msg.send(msg) 28 | 29 | sys.exit(0) 30 | -------------------------------------------------------------------------------- /flightcode/stm32/set_telem_units_msg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import socket 4 | 5 | # Must match flightcode/stm32 and/or config/sololink.orig 6 | SET_TELEM_UNITS_PORT = 5024 7 | 8 | # Send message to STM32 via stm32 process 9 | # 10 | # Message is a single byte: 0=imperial, 1=metric; 11 | # does not have the one-byte packet ID at the start. 12 | 13 | def send(msg): 14 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 15 | s.sendto(msg, ("127.0.0.1", SET_TELEM_UNITS_PORT)) 16 | s.close() 17 | 18 | def pack_msg(is_metric): 19 | if is_metric: 20 | return chr(1) 21 | else: 22 | return chr(0) 23 | 24 | def unpack(msg): 25 | return (ord(msg[0]) != 0) 26 | -------------------------------------------------------------------------------- /flightcode/stm32/updater_msg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Show update status screens: updating system, update complete, update failed 4 | 5 | import socket 6 | import struct 7 | import sys 8 | 9 | START = 0 10 | SUCCESS = 1 11 | FAIL = 2 12 | 13 | # must match flightcode/stm32 14 | UPDATER_PORT = 5019 15 | 16 | def send(id): 17 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 18 | msg = struct.pack("!B", id) 19 | s.sendto(msg, ("127.0.0.1", UPDATER_PORT)) 20 | s.close() 21 | 22 | def send_start(): 23 | send(START) 24 | 25 | def send_success(): 26 | send(SUCCESS) 27 | 28 | def send_fail(): 29 | send(FAIL) 30 | 31 | def usage(): 32 | print "usage: updater_msg.py " 33 | print " where is one of" 34 | print " start show \"updating system\" screen" 35 | print " success show \"update complete\" screen" 36 | print " fail show \"update failed\" screen" 37 | 38 | if __name__ == "__main__": 39 | # one required argument: "start", "success", or "fail" 40 | if len(sys.argv) != 2: 41 | usage() 42 | elif sys.argv[1] == "start": 43 | send_start() 44 | elif sys.argv[1] == "success": 45 | send_success() 46 | elif sys.argv[1] == "fail": 47 | send_fail() 48 | else: 49 | usage() 50 | -------------------------------------------------------------------------------- /flightcode/telem/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util ../log ../ini ../ini/cpp 13 | 14 | INCS = -I../util -I../log -I../ini -I../ini/cpp 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) 18 | 19 | LIBS = -lpthread 20 | 21 | SRCS_CPP = telem_forward.cpp 22 | SRCS_CPP += RcLock.cpp 23 | SRCS_CPP += INIReader.cpp Log.cpp 24 | SRCS_C = util.c ini.c 25 | SRCS_C += file_util.c 26 | SRCS_C += syslog.c 27 | 28 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 29 | 30 | MAIN = telem_forwarder 31 | 32 | all: $(MAIN) 33 | 34 | $(MAIN): $(OBJS) 35 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 36 | 37 | clean: 38 | $(RM) *.o *~ $(MAIN) 39 | 40 | BASE := ../.. 41 | 42 | fmt: 43 | @python $(BASE)/tools/build/clang-format-run.py --apply 44 | 45 | fmt-diff: 46 | @python $(BASE)/tools/build/clang-format-run.py 47 | 48 | .PHONY: all clean fmt fmt-diff 49 | -------------------------------------------------------------------------------- /flightcode/telem/test_telem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | /*********************************************************************** 16 | UDP macros 17 | ***********************************************************************/ 18 | #define REMOTE_UDP_PORT 14560 19 | #define LOCAL_UDP_PORT 14550 20 | #define NUM_CHANNELS 8 21 | 22 | int main(void) 23 | { 24 | int sock_fd; 25 | struct sockaddr_in myaddr; 26 | struct sockaddr_in remaddr; /* server address */ 27 | int slen = sizeof(remaddr); 28 | socklen_t addrlen = sizeof(remaddr); /* length of addresses */ 29 | char *server = "127.0.0.1"; /* change this to use a different server */ 30 | char buf[512]; 31 | int recvlen; 32 | 33 | if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 34 | cerr << "cannot create socket" << endl; 35 | return 0; 36 | } 37 | 38 | memset((char *)&myaddr, 0, sizeof(myaddr)); 39 | myaddr.sin_family = AF_INET; 40 | myaddr.sin_addr.s_addr = htonl(INADDR_ANY); 41 | myaddr.sin_port = htons(LOCAL_UDP_PORT); 42 | 43 | if (bind(sock_fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { 44 | perror("bind failed"); 45 | return 0; 46 | } 47 | 48 | fcntl(sock_fd, F_SETFL, O_NONBLOCK); 49 | 50 | memset((char *)&remaddr, 0, sizeof(remaddr)); 51 | remaddr.sin_family = AF_INET; 52 | remaddr.sin_port = htons(REMOTE_UDP_PORT); 53 | if (inet_aton(server, &remaddr.sin_addr) == 0) { 54 | cerr << "inet_aton() failed" << endl; 55 | return 0; 56 | } 57 | 58 | memset(buf, 0, sizeof(buf)); 59 | sprintf(buf, "Hello!\n"); 60 | sendto(sock_fd, buf, strlen(buf), 0, (struct sockaddr *)&remaddr, slen); 61 | 62 | while (true) { 63 | // See if theres anything to receive 64 | memset(buf, 0, sizeof(buf)); 65 | recvlen = recvfrom(sock_fd, buf, 512, 0, (struct sockaddr *)&remaddr, &addrlen); 66 | 67 | if (recvlen > 0) 68 | cout << "Got " << recvlen << " bytes" << endl; 69 | } 70 | 71 | close(sock_fd); 72 | return 1; 73 | } 74 | -------------------------------------------------------------------------------- /flightcode/telem_ctrl/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util ../ini ../ini/cpp 13 | 14 | INCS = -I../util -I../ini -I../ini/cpp 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) 18 | 19 | LIBS = -lpthread -lrt 20 | 21 | SRCS_CPP = telem_ctrl.cpp 22 | SRCS_CPP += INIReader.cpp 23 | SRCS_CPP += telem_dest.cpp 24 | SRCS_C = arp_table.c hostapd_ctrl.c util.c ini.c 25 | SRCS_C += mutex.c 26 | SRCS_C += syslog.c 27 | 28 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 29 | 30 | MAIN = telem_ctrl 31 | 32 | all: $(MAIN) 33 | 34 | $(MAIN): $(OBJS) 35 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 36 | 37 | clean: 38 | $(RM) *.o *~ $(MAIN) 39 | 40 | BASE := ../.. 41 | 42 | fmt: 43 | @python $(BASE)/tools/build/clang-format-run.py --apply 44 | 45 | fmt-diff: 46 | @python $(BASE)/tools/build/clang-format-run.py 47 | 48 | .PHONY: all clean fmt fmt-diff 49 | -------------------------------------------------------------------------------- /flightcode/telem_ctrl/telem_dest.h: -------------------------------------------------------------------------------- 1 | #ifndef TELEM_DEST_H 2 | #define TELEM_DEST_H 3 | 4 | // 5 | // telemetry destinations table 6 | // 7 | // This is the destinations that receive mavlink. It is updated periodically 8 | // based on who is associated with the AP and who is in the ARP table. The 9 | // table's first 'num_dest' entries are in use, and all entries after that are 10 | // free. An entry is added by putting it at index 'num_dest'. An entry 'k' is 11 | // deleted by copying all entries from 'k' + 1 to the end down one slot 12 | // (overwriting the entry to be deleted) and clearing the one now at the end. 13 | // 14 | 15 | #ifndef MAC_LEN 16 | #define MAC_LEN 6 17 | #endif 18 | 19 | // Each entry either wants raw mavlink, or a link_packet (mavlink with 20 | // metadata wrapper). 21 | typedef enum { 22 | TF_MAVLINK, // raw mavlink 23 | TF_LINK_PACKET, // link_packet.h 24 | TF_MAX // (last) 25 | } telem_format_t; 26 | 27 | // one entry in table 28 | struct telem_dest { 29 | telem_format_t format; 30 | int fd; 31 | sockaddr_in sa; 32 | unsigned err_cnt; // send errors for this dest since last message 33 | uint64_t err_us; // time of last send error message 34 | uint8_t mac[MAC_LEN]; 35 | }; 36 | 37 | // the table (entries plus count) 38 | struct telem_dest_table { 39 | // Maximum number of destinations. Normally we have up to four: 40 | // two internal (stm32 and tlog), maybe an app, and maybe a gcs. 41 | static const int DEST_MAX = 32; 42 | 43 | telem_dest dest[DEST_MAX]; 44 | int num_dest; 45 | 46 | void init(void); 47 | void dump(int priority) const; 48 | void check(void) const; 49 | int add(const uint8_t *mac, const in_addr_t ip, const short port_hbo, int tos = 0, 50 | telem_format_t format = TF_MAVLINK); 51 | void delete_by_index(int index); 52 | int find_by_mac_ip(const uint8_t *mac, const in_addr_t ip) const; 53 | }; 54 | 55 | #endif // TELEM_DEST_H 56 | -------------------------------------------------------------------------------- /flightcode/telem_test/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util ../mavlink/c_library/ardupilotmega 13 | 14 | INCS = -I../util -I../mavlink/c_library/ardupilotmega 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) 18 | 19 | LIBS = -lpthread 20 | 21 | SRCS_CPP = telem_test.cpp 22 | SRCS_C = util.c 23 | 24 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 25 | 26 | MAIN = telem_test 27 | 28 | all: $(MAIN) 29 | 30 | $(MAIN): $(OBJS) 31 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 32 | 33 | clean: 34 | $(RM) *.o *~ $(MAIN) 35 | 36 | .PHONY: clean 37 | -------------------------------------------------------------------------------- /flightcode/thermal/log_temp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TEMPFILE=/sys/class/thermal/thermal_zone0/temp 4 | 5 | while true; do 6 | logger -t temp -p local5.info -- `cat $TEMPFILE` 7 | sleep 60 8 | done 9 | -------------------------------------------------------------------------------- /flightcode/tlog/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../log ../util 13 | 14 | INCS = -I../log -I../util 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) 18 | 19 | SRCS_CPP = tlog.cpp 20 | SRCS_CPP += Log.cpp 21 | SRCS_C += util.c 22 | 23 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 24 | 25 | MAIN = tlog 26 | 27 | all: $(MAIN) 28 | 29 | $(MAIN): $(OBJS) 30 | $(LINK.cpp) -o $(MAIN) $(OBJS) 31 | 32 | clean: 33 | $(RM) *.o *~ $(MAIN) 34 | $(RM) ../log/*.o 35 | $(RM) ../util/*.o 36 | 37 | BASE := ../.. 38 | 39 | fmt: 40 | @python $(BASE)/tools/build/clang-format-run.py --apply 41 | 42 | fmt-diff: 43 | @python $(BASE)/tools/build/clang-format-run.py 44 | 45 | .PHONY: all clean fmt fmt-diff 46 | -------------------------------------------------------------------------------- /flightcode/unlock/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../util 13 | 14 | INCS = -I../util 15 | 16 | CFLAGS += -Wall $(INCS) 17 | CXXFLAGS += -Wall $(INCS) 18 | 19 | BIN = unlock 20 | 21 | all: $(BIN) 22 | 23 | $(BIN): unlock.o ButtonEventMessage.o RcLock.o file_util.o 24 | $(LINK.cpp) -o $(BIN) unlock.o ButtonEventMessage.o RcLock.o file_util.o 25 | 26 | clean: 27 | $(RM) *.o *~ $(BIN) 28 | 29 | BASE := ../.. 30 | 31 | fmt: 32 | @python $(BASE)/tools/build/clang-format-run.py --apply 33 | 34 | fmt-diff: 35 | @python $(BASE)/tools/build/clang-format-run.py 36 | 37 | .PHONY: all clean fmt fmt-diff 38 | -------------------------------------------------------------------------------- /flightcode/util/ButtonEventMessage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ButtonEventMessage.h" 4 | 5 | using namespace std; 6 | 7 | // Send a ButtonEventMessage to a stream in a friendly format. 8 | ostream &operator<<(ostream &os, const struct ButtonEventMessage &msg) 9 | { 10 | os << "timestamp=" << msg.timestamp; 11 | os << " id=" << msg.idName(); 12 | os << " event=" << msg.eventName(); 13 | os << " allButtons=" << setfill('0') << setw(4) << hex << msg.allButtons; 14 | return os; 15 | } 16 | -------------------------------------------------------------------------------- /flightcode/util/ButtonEventMessage.h: -------------------------------------------------------------------------------- 1 | #ifndef BUTTON_EVENT_MESSAGE_H 2 | #define BUTTON_EVENT_MESSAGE_H 3 | 4 | #include 5 | #include 6 | 7 | struct __attribute((__packed__)) ButtonEventMessage { 8 | // These four fields are expected to be the only data and in this order, 9 | // so the address of the structure can be interpreted as a 12-byte char 10 | // array with the fields in native byte order (little-endian on ARM). 11 | uint64_t timestamp; 12 | uint8_t id; 13 | uint8_t event; 14 | uint16_t allButtons; 15 | 16 | // match artoo/src/io.h 17 | enum ButtonId { 18 | ButtonPower, 19 | ButtonFly, 20 | ButtonRTL, 21 | ButtonLoiter, 22 | ButtonA, 23 | ButtonB, 24 | ButtonPreset1, 25 | ButtonPreset2, 26 | ButtonCameraClick, 27 | ButtonMax 28 | }; 29 | 30 | inline const char *idName(void) const 31 | { 32 | static const char *names[] = { 33 | "Power", "Fly", "RTL", "Loiter", "A", "B", "Preset1", "Preset2", "CameraClick", 34 | }; 35 | if (id >= 0 && id < ButtonMax) 36 | return names[id]; 37 | else 38 | return "INVALID"; 39 | } 40 | 41 | // match artoo/src/button.h 42 | enum ButtonEvent { Press, Release, ClickRelease, ShortHold, Hold, LongHold, DoubleClick, HoldRelease, LongHoldRelease, EventMax }; 43 | 44 | inline const char *eventName(void) const 45 | { 46 | static const char *names[] = { 47 | "Press", "Release", "ClickRelease", "ShortHold", "Hold", "LongHold", "DoubleClick", "HoldRelease", "LongHoldRelease", 48 | }; 49 | if (event >= 0 && event < EventMax) 50 | return names[event]; 51 | else 52 | return "INVALID"; 53 | } 54 | 55 | ButtonEventMessage(void) 56 | { 57 | timestamp = 0; 58 | id = 0; 59 | event = 0; 60 | allButtons = 0; 61 | } 62 | 63 | ButtonEventMessage(uint64_t ts, const char *rawMsg) 64 | { 65 | timestamp = ts; 66 | // rawMsg is ButtonEvent in artoo/src/buttonmanager.h 67 | id = rawMsg[0]; 68 | event = rawMsg[1]; 69 | allButtons = rawMsg[2] | (rawMsg[3] << 8); // little endian 70 | } 71 | }; 72 | 73 | std::ostream &operator<<(std::ostream &os, const struct ButtonEventMessage &msg); 74 | 75 | #endif // BUTTON_EVENT_MESSAGE_H 76 | -------------------------------------------------------------------------------- /flightcode/util/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS += -Wall 3 | 4 | syslog_test.o : CFLAGS += -Wno-format-security 5 | 6 | syslog_test.o syslog.o : CFLAGS += -D SYSLOG_SOCK_NAME=\"/tmp/syslog_test\" 7 | syslog_test.o syslog.o : CFLAGS += -D SYSLOG_MSG_MAX=64 8 | 9 | CFLAGS += $(INCS) 10 | 11 | SRCS_C = main.c \ 12 | util.c util_test.c \ 13 | syslog.c syslog_test.c 14 | 15 | OBJS = $(SRCS_C:.c=.o) 16 | 17 | MAIN = util_test 18 | 19 | all: $(MAIN) 20 | 21 | $(MAIN): $(OBJS) 22 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 23 | 24 | clean: 25 | $(RM) *.o *~ $(MAIN) 26 | 27 | BASE := ../.. 28 | 29 | fmt: 30 | @python $(BASE)/tools/build/clang-format-run.py --apply 31 | 32 | fmt-diff: 33 | @python $(BASE)/tools/build/clang-format-run.py 34 | 35 | .PHONY: all clean fmt fmt-diff 36 | -------------------------------------------------------------------------------- /flightcode/util/RcLock.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "file_util.h" 6 | #include "RcLock.h" 7 | 8 | namespace RcLock 9 | { 10 | 11 | // must match rc_lock.py 12 | static const char *ro_lockfile = "/mnt/rootfs.ro/etc/.rc_lock"; 13 | static const char *tmp_lockfile = "/tmp/.rc_lock"; 14 | static const char *tmp_unlockfile = "/tmp/.rc_unlock"; 15 | 16 | // locked - see if RC is locked 17 | // 18 | // Returns true if RC is locked, false if not locked. 19 | bool locked(void) 20 | { 21 | 22 | if (file_exists(tmp_unlockfile)) 23 | return false; 24 | else if (file_exists(tmp_lockfile) || file_exists(ro_lockfile)) 25 | return true; 26 | else 27 | return false; 28 | } 29 | 30 | // lock_version - lock RC due to version mismatch 31 | void lock_version(void) 32 | { 33 | file_touch(tmp_lockfile); 34 | } 35 | 36 | // unlock_version - unlock RC (versions match) 37 | void unlock_version(void) 38 | { 39 | unlink(tmp_lockfile); 40 | } 41 | 42 | // unlock_override - unlock RC 43 | void unlock_override(void) 44 | { 45 | file_touch(tmp_unlockfile); 46 | } 47 | 48 | } // namespace RcLock 49 | -------------------------------------------------------------------------------- /flightcode/util/RcLock.h: -------------------------------------------------------------------------------- 1 | #ifndef RC_LOCK_H 2 | #define RC_LOCK_H 3 | 4 | namespace RcLock 5 | { 6 | 7 | extern bool locked(void); 8 | extern void lock_version(void); 9 | extern void unlock_version(void); 10 | extern void unlock_override(void); 11 | 12 | } // namespace RcLock 13 | 14 | #endif // RC_LOCK_H 15 | -------------------------------------------------------------------------------- /flightcode/util/arp_table.h: -------------------------------------------------------------------------------- 1 | #ifndef ARP_TABLE_H 2 | #define ARP_TABLE_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #ifndef MAC_LEN 12 | #define MAC_LEN 6 13 | #endif 14 | #define DEV_NAME_MAX 16 15 | 16 | typedef struct { 17 | in_addr_t ip; /* IP in network byte order */ 18 | unsigned hw_type; 19 | unsigned flags; 20 | uint8_t mac[MAC_LEN]; 21 | char dev[DEV_NAME_MAX]; 22 | } arp_entry_t; 23 | 24 | extern int arp_table_get(arp_entry_t *arp_table, int *arp_entries); 25 | extern int arp_table_find_by_ip(arp_entry_t *arp_table, int arp_entries, in_addr_t ip); 26 | extern void arp_table_dump(int priority, const arp_entry_t *arp_table, int arp_entries); 27 | 28 | #ifdef __cplusplus 29 | }; 30 | #endif 31 | 32 | #endif /* ARP_TABLE_H */ 33 | -------------------------------------------------------------------------------- /flightcode/util/file_util.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "file_util.h" 7 | 8 | /* 9 | * file_exists - determine whether a file exists 10 | * 11 | * Return nonzero (true) if file exists, zero (false) if file does not exist. 12 | */ 13 | int file_exists(const char *filename) 14 | { 15 | struct stat file_stat; 16 | return (stat(filename, &file_stat) == 0); 17 | } 18 | 19 | /* 20 | * file_touch - create file if it does not exist 21 | * 22 | * Method of doing this (the mode flags) is per 'man touch'. 23 | */ 24 | int file_touch(const char *filename) 25 | { 26 | int fd; 27 | mode_t mode; 28 | 29 | mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 30 | 31 | fd = creat(filename, mode); 32 | if (fd < 0) { 33 | return 0; 34 | } else { 35 | close(fd); 36 | return 1; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /flightcode/util/file_util.h: -------------------------------------------------------------------------------- 1 | #ifndef FILE_UTIL_H 2 | #define FILE_UTIL_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | extern int file_exists(const char *filename); 9 | extern int file_touch(const char *filename); 10 | 11 | #ifdef __cplusplus 12 | }; 13 | #endif 14 | 15 | #endif /* FILE_UTIL_H */ 16 | -------------------------------------------------------------------------------- /flightcode/util/hostapd_ctrl.h: -------------------------------------------------------------------------------- 1 | #ifndef HOSTAPD_CTRL_H 2 | #define HOSTAPD_CTRL_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #ifndef MAC_LEN 9 | #define MAC_LEN 6 10 | #endif 11 | 12 | extern void *hostapd_ctrl_new(const char *ifname); 13 | extern int hostapd_ctrl_delete(void *handle); 14 | 15 | typedef struct { 16 | uint8_t mac[MAC_LEN]; 17 | /* more fields are available, but not parsed */ 18 | } hostapd_station_info_t; 19 | 20 | extern int hostapd_ctrl_get_stations(const void *handle, hostapd_station_info_t *station_info, 21 | int *station_entries); 22 | extern int hostapd_ctrl_find_by_mac(const hostapd_station_info_t *station_info, int station_entries, 23 | const uint8_t *mac); 24 | 25 | #ifdef __cplusplus 26 | }; 27 | #endif 28 | 29 | #endif /* HOSTAPD_CTRL_H */ 30 | -------------------------------------------------------------------------------- /flightcode/util/link_packet.h: -------------------------------------------------------------------------------- 1 | #ifndef LINK_PACKET_H 2 | #define LINK_PACKET_H 3 | 4 | #include 5 | 6 | struct LinkPacket { 7 | static const int MAX_PAYLOAD = 1444; /* MTU minus the header */ 8 | 9 | uint64_t tf_recv_us; 10 | uint64_t tf_send_us; 11 | uint64_t tc_recv_us; 12 | uint64_t tc_send_us; 13 | uint64_t stm_recv_us; 14 | uint32_t seq; 15 | uint32_t data1; 16 | uint32_t data2; 17 | uint32_t data3; 18 | uint8_t payload[MAX_PAYLOAD]; 19 | 20 | // everything but the payload 21 | static const int HDR_LEN = 56; 22 | }; 23 | 24 | #endif // LINK_PACKET_H 25 | -------------------------------------------------------------------------------- /flightcode/util/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "util_test.h" 4 | #include "syslog_test.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | 9 | fprintf(stderr, "util_test..."); 10 | if (util_test() == 0) 11 | fprintf(stderr, "pass\n"); 12 | else 13 | fprintf(stderr, "FAIL\n"); 14 | 15 | fprintf(stderr, "syslog_test..."); 16 | if (syslog_test() == 0) 17 | fprintf(stderr, "pass\n"); 18 | else 19 | fprintf(stderr, "FAIL\n"); 20 | 21 | return 0; 22 | 23 | } // main 24 | -------------------------------------------------------------------------------- /flightcode/util/mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef MUTEX_H 2 | #define MUTEX_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | extern void mutex_attr_show(const pthread_mutexattr_t *attr); 12 | extern int mutex_init(pthread_mutex_t *mutex); 13 | extern int mutex_lock(pthread_mutex_t *mutex, uint64_t *max_blocked_us); 14 | extern int mutex_unlock(pthread_mutex_t *mutex); 15 | 16 | #ifdef __cplusplus 17 | }; 18 | #endif 19 | 20 | #endif /* MUTEX_H */ 21 | -------------------------------------------------------------------------------- /flightcode/util/net_stats.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_STATS_H 2 | #define NET_STATS_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | typedef struct { 9 | unsigned rx_queue; 10 | } udp_info_t; 11 | 12 | extern int udp_info_get(unsigned port, udp_info_t *info); 13 | 14 | #ifdef __cplusplus 15 | }; 16 | #endif 17 | 18 | #endif /* NET_STATS_H */ 19 | -------------------------------------------------------------------------------- /flightcode/util/net_wmm.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_WMM_H 2 | #define NET_WMM_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #define IP_TOS_DEFAULT 0 /* default (best effort) */ 9 | #define IP_TOS_BK (1 << 5) /* background, lowest */ 10 | #define IP_TOS_BE (3 << 5) /* best effort, default */ 11 | #define IP_TOS_VI (5 << 5) /* video */ 12 | #define IP_TOS_VO (7 << 5) /* voice, highest */ 13 | 14 | #ifdef __cplusplus 15 | }; 16 | #endif 17 | 18 | #endif /* NET_WMM_H */ 19 | -------------------------------------------------------------------------------- /flightcode/util/syslog_test.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSLOG_TEST_H 2 | #define SYSLOG_TEST_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | extern int syslog_test(void); 9 | 10 | #ifdef __cplusplus 11 | }; 12 | #endif 13 | 14 | #endif /* SYSLOG_TEST_H */ 15 | -------------------------------------------------------------------------------- /flightcode/util/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #include 5 | 6 | #if (defined __MACH__ && defined __APPLE__) 7 | typedef int clockid_t; 8 | #define CLOCK_REALTIME 0 9 | #define CLOCK_MONOTONIC 1 10 | #else 11 | #include 12 | #endif 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | extern uint64_t clock_gettime_us(clockid_t clock_id); 19 | extern void clock_settime_us(clockid_t clock_id, uint64_t t_us); 20 | extern const char *clock_tostr_r(uint64_t t_us, char *buf); 21 | extern const char *clock_gettime_str_r(clockid_t clock_id, char *buf); 22 | extern int hex_aton(char a); 23 | #define MAC_STRING_LEN 18 24 | extern char *mac_ntoa(uint8_t *mac_bytes, char *mac_string); 25 | extern uint8_t *mac_aton(const char *mac_string, uint8_t *mac_bytes); 26 | 27 | #ifdef __cplusplus 28 | }; 29 | #endif 30 | 31 | #endif /* UTIL_H */ 32 | -------------------------------------------------------------------------------- /flightcode/util/util_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "util.h" 5 | #include "util_test.h" 6 | 7 | int util_test(void) 8 | { 9 | int status = 0; 10 | uint64_t t0, t1; 11 | 12 | // CLOCK_REALTIME incrementing 13 | t0 = clock_gettime_us(CLOCK_REALTIME); 14 | usleep(10000); 15 | t1 = clock_gettime_us(CLOCK_REALTIME); 16 | if (t1 == t0) { 17 | fprintf(stderr, "util_test: CLOCK_REALTIME did not change\n"); 18 | status = 1; 19 | goto util_test_exit_0; 20 | } 21 | 22 | // CLOCK_MONOTONIC incrementing 23 | t0 = clock_gettime_us(CLOCK_MONOTONIC); 24 | usleep(10000); 25 | t1 = clock_gettime_us(CLOCK_MONOTONIC); 26 | if (t1 == t0) { 27 | fprintf(stderr, "util_test: CLOCK_MONOTONIC did not change\n"); 28 | status = 1; 29 | goto util_test_exit_0; 30 | } 31 | 32 | util_test_exit_0: 33 | return status; 34 | 35 | } // util_test 36 | -------------------------------------------------------------------------------- /flightcode/util/util_test.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_TEST_H 2 | #define UTIL_TEST_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | extern int util_test(void); 9 | 10 | #ifdef __cplusplus 11 | }; 12 | #endif 13 | 14 | #endif /* UTIL_TEST_H */ 15 | -------------------------------------------------------------------------------- /flightcode/video/README: -------------------------------------------------------------------------------- 1 | The Solo video pipeline exists in this folder. The pipeline works as follows: 2 | 3 | ================= 4 | | | 5 | | SOLO | 6 | | | 7 | | vidout | 8 | ================= 9 | | 10 | | 11 | | 12 | V 13 | ================= 14 | | app_streamer | ========== 15 | | | | | | | 16 | | | ARTOO >-->|----->| mobile | 17 | | | | | | 18 | | -> hdmiout | ========== 19 | ================= 20 | | 21 | | 22 | | 23 | V 24 | ================= 25 | | MONITOR | 26 | ================= 27 | 28 | vidout: 29 | vidout is always running on Solo and handles resolution size changes 30 | automatically. It always sends rtp-encapsulated h.264 720p video 31 | to Artoo on port 5550. Depending on network conditions, it will reduce 32 | the framerate of the video. Specifically, if the number of transmit 33 | retries on Solo eclipses 200, the framerate will be reduced based on the 34 | following: 35 | 36 | 30fps -> 24fps -> 15fps -> 10fps -> 5fps 37 | 38 | If the link continues to be bad, the framerate is held at 5fps. Further work 39 | could reduce the GOP or QUANT to reduce bitrate even further. Additional 40 | work should be done to support streaming different resolutions as well. 41 | 42 | app_streamer: 43 | app_streamer on Artoo takes data from port 5550 and passes it to 44 | both the hdmiout as well as any connected mobile devices. It sends full 45 | frames at a time to mobile devices, but passes data byte-by-byte to hdmiout. 46 | 47 | hdmiout: 48 | hdmiout is always running, but waits to detect a connected HDMI cable before 49 | starting the decoding pipeline. It puts 720p video out on the HDMI port of Artoo 50 | using the mfw_isink gstreamer plugin. 51 | 52 | cleanlibs.sh: 53 | cleanlibs is used to remove old Sculpture libraries that are no longer in use. 54 | This is installed as a startup script, but can probably be removed in the future. 55 | -------------------------------------------------------------------------------- /flightcode/video/app/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../../util ../../ini ../../ini/cpp 13 | INCS = -I../../util -I../../ini -I../../ini/cpp 14 | 15 | CFLAGS += -Wall $(INCS) 16 | CXXFLAGS += -Wall $(INCS) 17 | 18 | LIBS = 19 | 20 | SRCS_CPP = app_streamer.cpp 21 | SRCS_CPP += INIReader.cpp 22 | SRCS_C = util.c 23 | SRCS_C += ini.c 24 | 25 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 26 | 27 | MAIN = app_streamer 28 | 29 | all: $(MAIN) 30 | 31 | $(MAIN): $(OBJS) 32 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 33 | 34 | clean: 35 | $(RM) *.o *~ $(MAIN) 36 | 37 | BASE := ../../.. 38 | 39 | fmt: 40 | @python $(BASE)/tools/build/clang-format-run.py --apply 41 | 42 | fmt-diff: 43 | @python $(BASE)/tools/build/clang-format-run.py 44 | 45 | .PHONY: all clean fmt fmt-diff 46 | -------------------------------------------------------------------------------- /flightcode/video/cleanLibs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RWFS=/mnt/rootfs.rw 4 | LIBDIR=/usr/lib 5 | 6 | if [ -e $RWFS/$LIBDIR/sndast* ] || 7 | [ -e $RWFS/$LIBDIR/libvpu* ] || 8 | [ -e $RWFS/$LIBDIR/libfsl* ] || 9 | [ -e $RWFS/$LIBDIR/gstrea* ] ; then 10 | 11 | #Remove all the sculpture libraries 12 | rm -rf $RWFS/$LIBDIR/sndast 13 | rm -rf $RWFS/$LIBDIR/libvpu* 14 | rm -rf $RWFS/$LIBDIR/libfslvpu* 15 | rm -rf $RWFS/$LIBDIR/gstreamer* 16 | rm -rf $RWFS/$LIBDIR/.*libfslvpu* 17 | 18 | #Remove the gstreamer registry 19 | rm -f ~/.gstreamer-0.10/registry.arm.bin 20 | 21 | #Rebuild the gstreamer library 22 | gst-inspect > /dev/null 2>&1 23 | 24 | fi 25 | -------------------------------------------------------------------------------- /flightcode/video/hdmi/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | PKGCONFIG = `pkg-config gstreamer-0.10 --cflags --libs` 13 | 14 | CFLAGS += $(PKGCONFIG) 15 | CFLAGS += -Wall 16 | 17 | all: out 18 | 19 | out: 20 | $(CC) $(CFLAGS) hdmiout.c -o hdmiout 21 | 22 | clean: 23 | $(RM) *.o *~ hdmiout 24 | 25 | BASE := ../../.. 26 | 27 | fmt: 28 | @python $(BASE)/tools/build/clang-format-run.py --apply 29 | 30 | fmt-diff: 31 | @python $(BASE)/tools/build/clang-format-run.py 32 | 33 | .PHONY: all clean fmt fmt-diff 34 | -------------------------------------------------------------------------------- /flightcode/video/vid/80211.h: -------------------------------------------------------------------------------- 1 | #ifndef __80211_H__ 2 | #define __80211_H__ 3 | 4 | int get_retries(void); 5 | 6 | #endif //__80211_H_ 7 | -------------------------------------------------------------------------------- /flightcode/video/vid/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | PKGCONFIG = `pkg-config gstreamer-0.10 --cflags --libs` 13 | 14 | VPATH = ../../ini ../../ini/cpp 15 | 16 | INCS = -I../../ini -I../../ini/cpp -I$(OECORE_TARGET_SYSROOT)/usr/include/libnl3 17 | 18 | CFLAGS += -Wall $(INCS) 19 | CXXFLAGS += -Wall $(INCS) $(PKGCONFIG) 20 | 21 | LIBS = -lnl-3 -lnl-genl-3 22 | 23 | SRCS_CPP = INIReader.cpp 24 | SRCS_CPP += vidlaunch.cpp 25 | SRCS_CPP += 80211.cpp 26 | SRCS_C += ini.c 27 | 28 | OBJS = $(SRCS_CPP:.cpp=.o) $(SRCS_C:.c=.o) 29 | 30 | MAIN = vidlaunch 31 | 32 | all: $(MAIN) 33 | 34 | $(MAIN): $(OBJS) 35 | $(LINK.cpp) -o $(MAIN) $(OBJS) $(LIBS) 36 | 37 | clean: 38 | $(RM) *.o *~ $(MAIN) *Test 39 | 40 | BASE := ../../.. 41 | 42 | fmt: 43 | @python $(BASE)/tools/build/clang-format-run.py --apply 44 | 45 | fmt-diff: 46 | @python $(BASE)/tools/build/clang-format-run.py 47 | 48 | .PHONY: all clean fmt fmt-diff 49 | -------------------------------------------------------------------------------- /flightcode/wdog/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | CFLAGS += -Wall $(INCS) 13 | 14 | SRCS_C = wdog.c 15 | 16 | OBJS = $(SRCS_C:.c=.o) 17 | 18 | MAIN = wdog 19 | 20 | all: $(MAIN) 21 | 22 | $(MAIN): $(OBJS) 23 | $(LINK.c) -o $(MAIN) $(OBJS) 24 | 25 | clean: 26 | $(RM) *.o *~ $(MAIN) 27 | 28 | BASE := ../.. 29 | 30 | fmt: 31 | @python $(BASE)/tools/build/clang-format-run.py --apply 32 | 33 | fmt-diff: 34 | @python $(BASE)/tools/build/clang-format-run.py 35 | 36 | .PHONY: all clean fmt fmt-diff 37 | -------------------------------------------------------------------------------- /gimbal/firmware_helper.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Helper functions to work with firmware files 3 | ''' 4 | import base64 5 | import zlib 6 | import json 7 | 8 | 9 | def bytearray_to_wordarray(data): 10 | '''Converts an 8-bit byte array into a 16-bit word array''' 11 | wordarray = list() 12 | 13 | for i in range(len(data) / 2): 14 | # Calculate 16 bit word from two bytes 15 | msb = data[(i * 2) + 0] 16 | lsb = data[(i * 2) + 1] 17 | word = (msb << 8) | lsb 18 | wordarray.append(word) 19 | 20 | return wordarray 21 | 22 | def add_checksum(checksum, word): 23 | '''Simple XOR checksum''' 24 | checksum ^= word 25 | return checksum 26 | 27 | def append_checksum(binary): 28 | '''Calculate and append the XOR checksum to the bytearray''' 29 | checksum = 0xFFFF 30 | wordarray = bytearray_to_wordarray(binary) 31 | 32 | # Compute the checksum 33 | for i in range(len(wordarray)): 34 | checksum ^= wordarray[i] 35 | 36 | # Add the checksum to the end of the wordarray 37 | wordarray.extend([checksum & 0xFFFF, (checksum & 0xFFFF) >> 16, 0x0000]) 38 | 39 | # Convert the wordarray back into a bytearray 40 | barray = list() 41 | for i in range(len(wordarray)): 42 | lsb = wordarray[i] & 0xFF 43 | msb = (wordarray[i] >> 8) & 0xFF 44 | barray.append(lsb) 45 | barray.append(msb) 46 | 47 | return barray, checksum 48 | 49 | def load_firmware(filename): 50 | '''Load the image from the JSON firmware file into a byte array''' 51 | with open(filename, "r") as f: 52 | desc = json.load(f) 53 | desc['binary'] = bytearray(zlib.decompress(base64.b64decode(desc['image']))) 54 | return desc 55 | 56 | 57 | def load_binary(filename): 58 | '''Load binary image file into a byte array''' 59 | with open(filename, "rb") as f: 60 | return bytearray(f.read()) 61 | -------------------------------------------------------------------------------- /gimbal/setup_factory_pub.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import setup_param 3 | 4 | def float_to_uint32(f): 5 | return struct.unpack('I',struct.pack('f', f)) 9 | 10 | def float3_to_string12(f1, f2, f3): 11 | return struct.unpack('12s',struct.pack('<3f', f1, f2, f3))[0] 12 | 13 | def get_assembly_time(link): 14 | value = setup_param.fetch_param(link, "GMB_ASM_TIME", timeout=1) 15 | if value: 16 | return float_to_uint32(value.param_value) 17 | return None 18 | 19 | def read_software_version(link, timeout=1): 20 | msg = setup_param.fetch_param(link, "GMB_SWVER", timeout=timeout) 21 | if not msg: 22 | return None 23 | else: 24 | return float_to_bytes4(msg.param_value)[:-1] 25 | 26 | def get_serial_number(link): 27 | ser_num_1 = setup_param.fetch_param(link, "GMB_SER_NUM_1", timeout=1) 28 | ser_num_2 = setup_param.fetch_param(link, "GMB_SER_NUM_2", timeout=1) 29 | ser_num_3 = setup_param.fetch_param(link, "GMB_SER_NUM_3", timeout=1) 30 | if ser_num_1 != None and ser_num_2 != None and ser_num_3 != None: 31 | serial_str = float3_to_string12(ser_num_1.param_value, ser_num_2.param_value, ser_num_3.param_value) 32 | if serial_str.startswith('GB'): 33 | return serial_str 34 | else: 35 | return '' 36 | return None 37 | -------------------------------------------------------------------------------- /init/3dr_rotate: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "rotating 3dr logs" 4 | 5 | if [ -f /usr/sbin/logrotate ]; then 6 | logrotate -f /etc/logrotate-sololink.conf -s /dev/null 7 | fi 8 | 9 | if [ "`hostname`" == "3dr_solo" ]; then 10 | 11 | # Set links to shotlogs for backwards compatibility (external fetchers). 12 | # Use of the three-digit-number names should be considered deprecated. 13 | # 14 | # shotlog.000.log -> shotlog.log 15 | # shotlog.001.log -> shotlog.log.1 16 | # shotlog.002.log -> shotlog.log.2 17 | # : 18 | # shotlog.019.log -> shotlog.log.19 19 | # 20 | # This should be done after the rotate above, so the files have the names they 21 | # will have for this run. 22 | 23 | cd /log 24 | 25 | # on first boot, shotlog.log is not there 26 | # (don't know why logrotate is not creating it empty) 27 | ln -sf shotlog.log shotlog.000.log 28 | 29 | for n in 1 2 3 4 5 6 7 8 9; do 30 | if [ -f shotlog.log.$n ]; then 31 | ln -sf shotlog.log.$n shotlog.00$n.log 32 | fi 33 | done 34 | 35 | for n in 10 11 12 13 14 15 16 17 18 19; do 36 | if [ -f shotlog.log.$n ]; then 37 | ln -sf shotlog.log.$n shotlog.0$n.log 38 | fi 39 | done 40 | 41 | fi 42 | -------------------------------------------------------------------------------- /init/clock_sync: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Normally, /etc/timestamp is update in a shutdown script. 4 | # 5 | # However, on Solo, we do not shut down; power just disappears. 6 | # 7 | # The goal of this script is to make time move forward, more-or-less, between 8 | # runs, i.e. all logs from one run should have timestamps greater than those 9 | # in logs from a previous run. /etc/timestamp only has minute-resolution, so 10 | # there can be overlap of up to about a minute between the very end of one 11 | # run and the very beginning of the next run. 12 | # 13 | # This is started by init and runs as long as the system is up. 14 | # 15 | # This only runs on Solo; Artoo is expected to get a power-button shutdown. 16 | # 17 | # Implementation note: Since power just disappears, we try to update 18 | # /etc/timestamp in a way such that it is always has valid contents. If we 19 | # just > into it, there may be a short time period when it is empty or does 20 | # not exist. The goal of writing a temp file, then doing a move, is to reduce 21 | # or eliminate the time window when it does not exist. 22 | 23 | while true; do 24 | date -u +%4Y%2m%2d%2H%2M > /etc/timestamp.new 25 | mv /etc/timestamp.new /etc/timestamp 26 | sleep 10 27 | done 28 | -------------------------------------------------------------------------------- /init/golden_to_system.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: Auto update from recovery 4 | # Required-Start: 5 | # Required-Stop: 6 | # Default-Start: 4 7 | # Default-Stop: 8 | # Short-Description: Auto update from recovery to system after factory reset 9 | ### END INIT INFO 10 | 11 | echo "Beginning golden_to_system.sh update script." 12 | 13 | isGolden() { 14 | boot_dev=`grep 'boot' /proc/mounts | awk '{print $1}'` 15 | # boot_dev should be either: 16 | # /dev/mmcblk0p1 when running golden, or 17 | # /dev/mmcblk0p2 when running latest 18 | if [ ${boot_dev} == "/dev/mmcblk0p1" ]; then 19 | echo "Boot is on recovery partition" 20 | return 0 21 | elif [ ${boot_dev} == "/dev/mmcblk0p2" ]; then 22 | echo "Boot is on system partition" 23 | return 1 24 | else 25 | echo "Can't determine boot partition" 26 | return 1 27 | fi 28 | } 29 | 30 | makeFilename() { 31 | if [ -f "/mnt/boot/imx6solo-3dr-1080p.dtb" ]; then 32 | updateFilename="solo_1.1.0.tar.gz" 33 | return 0 34 | elif [ -f "/mnt/boot/imx6solo-3dr-artoo.dtb" ]; then 35 | updateFilename="controller_1.1.0.tar.gz" 36 | return 0 37 | else 38 | return 1 39 | fi 40 | } 41 | 42 | makeSystem() { 43 | # Makes the golden image boot partition into a system update 44 | sololink_config --update-prepare sololink 45 | cd /mnt/boot 46 | tar -czvf /log/updates/$updateFilename * 47 | cd /log/updates 48 | md5sum "$updateFilename" > "$updateFilename".md5 49 | ls -lh /log/updates/ 50 | sed -i '1s/.*/golden/' /VERSION 51 | echo "Applying Update" 52 | sololink_config --update-apply sololink 53 | } 54 | 55 | if ! isGolden; then 56 | # If we're not on the recovery partion, there is nothing to do, so exit. 57 | echo "Not on recovery partition. Nothing to do. Exiting." 58 | exit 0 59 | fi 60 | 61 | echo "Creating recovery_to_system.log in /log/ directory." 62 | exec > /log/recovery_to_system.log 63 | exec 2>&1 64 | 65 | updateFilename=nothing 66 | if ! makeFilename; then 67 | echo "Couldn't make update filename. Aborting update. See log." 68 | exit 1 69 | fi 70 | echo "updateFilename is $updateFilename" 71 | 72 | if ! makeSystem; then 73 | echo "Making system update failed. Aborting. See log." 74 | exit 1 75 | fi 76 | -------------------------------------------------------------------------------- /init/pixhawk: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "initializing pixhawk interface..." 3 | /usr/bin/pixhawk.py -i 4 | -------------------------------------------------------------------------------- /init/shutdownArtoo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | IMX_POWER=21 4 | BOARD_POWER=19 5 | GPIODIR=/sys/class/gpio 6 | 7 | #sync, shutdown hard drives 8 | /sbin/halt -w -h 9 | 10 | echo $BOARD_POWER >> $GPIODIR/export 11 | echo out >> $GPIODIR/gpio$BOARD_POWER/direction 12 | echo 0 >> $GPIODIR/gpio$BOARD_POWER/value 13 | 14 | echo $IMX_POWER >> $GPIODIR/export 15 | echo out >> $GPIODIR/gpio$IMX_POWER/direction 16 | echo 0 >> $GPIODIR/gpio$IMX_POWER/value 17 | 18 | # 19 | # the stm32 is ready to shut down before we are, 20 | # but we rely on it to wait for us, so that the entire 21 | # system can agree that we're powered down. 22 | # 23 | # rough timeline: 24 | # - stm32 gets hold-pwr-button-to-shutdown gesture, sends please-shutdown msg 25 | # - imx6 starts shutting down, stm32 shows progress spinner & keeps power to imx6 enabled 26 | # - stm32 waits a hard coded duration for imx6 shutdown to complete. would prefer to timeout on a heartbeat, or similar. 27 | # - stm32 ensures power button has been released long enough for rc circuit to discharge 28 | # - stm32 disables power to the imx6 and either turns off if charger is not there, or goes to sleep 29 | # -------------------------------------------------------------------------------- /init/startwd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "starting watchdog..." 3 | /usr/bin/wdog -t 15 4 | -------------------------------------------------------------------------------- /init/updateGimbal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /usr/bin/loadGimbal.py 3 | -------------------------------------------------------------------------------- /net/etc/init.d/hostapd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | DAEMON=/usr/sbin/hostapd 3 | NAME=hostapd 4 | DESC="HOSTAP Daemon" 5 | HOSTAPD_CONF="/etc/hostapd.conf" 6 | HOSTAPD_BACK="/etc/hostapd.back" 7 | ARGS="/etc/hostapd.conf -B" 8 | SOLO_CONF="/etc/sololink.conf" 9 | 10 | test -f $DAEMON || exit 0 11 | 12 | set -e 13 | 14 | # Return true if parameter ($2) in config file ($1) is "True" 15 | isEnabled() { 16 | grep -i -q "[[:space:]]*$2[[:space:]]*=[[:space:]]*True" $1 17 | } 18 | 19 | # Return true if the SSID in hostapd.conf is still the default 20 | isDefault() { 21 | grep -i -q "^ssid=SoloLink_Default" $1 22 | } 23 | 24 | #Return the country code we should be using 25 | getCountryCode() { 26 | mkdir -p /tmp/bootmnt 27 | mount /dev/mmcblk0p1 /tmp/bootmnt -o ro 28 | if [ ! -e /tmp/bootmnt/.reg ]; then 29 | echo "US" 30 | else 31 | cat /tmp/bootmnt/.reg 32 | fi 33 | umount /tmp/bootmnt 34 | rm -rf /tmp/bootmnt 35 | } 36 | 37 | case "$1" in 38 | start) 39 | # If the 3dr config file does not exist, or if it does and ApEnable 40 | # is True, start hostapd 41 | if [ ! -f $SOLO_CONF ] || isEnabled $SOLO_CONF ApEnable; then 42 | echo -n "Starting $DESC: " 43 | # back up hostapd.conf 44 | cp ${HOSTAPD_CONF} ${HOSTAPD_BACK} 45 | md5sum ${HOSTAPD_BACK} > ${HOSTAPD_BACK}.md5 46 | sync 47 | # Unique-ize the SSID if it has not been done 48 | if isDefault ${HOSTAPD_CONF}; then 49 | # update SSID 50 | /usr/bin/hostapdconfig.py --ssid SoloLink_ --ssidmac wlan0-ap 51 | # initialize regulatory domain 52 | /usr/bin/hostapdconfig.py --country `getCountryCode` 53 | fi 54 | # set channel to that of wlan0 if it is associated 55 | /usr/bin/hostapdconfig.py --channel wlan0 56 | md5sum ${HOSTAPD_CONF} > ${HOSTAPD_CONF}.md5 57 | sync 58 | rm ${HOSTAPD_BACK} ${HOSTAPD_BACK}.md5 59 | sync 60 | start-stop-daemon -S -x $DAEMON -- $ARGS 61 | echo "$NAME." 62 | fi 63 | ;; 64 | stop) 65 | echo -n "Stopping $DESC: " 66 | start-stop-daemon -K -x $DAEMON 67 | echo "$NAME." 68 | ;; 69 | restart) 70 | $0 stop 71 | $0 start 72 | ;; 73 | reload) 74 | echo -n "Reloading $DESC: " 75 | killall -HUP $(basename ${DAEMON}) 76 | echo "$NAME." 77 | ;; 78 | *) 79 | echo "Usage: $0 {start|stop|restart|reload}" 80 | exit 1 81 | ;; 82 | esac 83 | 84 | exit 0 85 | -------------------------------------------------------------------------------- /net/etc/init.d/netinit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | NAME=wlan0-ap 4 | DESC="AP Interface" 5 | SOLO_CONF="/etc/sololink.conf" 6 | 7 | # Return true if parameter ($2) in config file ($1) is "True" 8 | isEnabled() { 9 | grep -i -q "[[:space:]]*$2[[:space:]]*=[[:space:]]*True" $1 10 | } 11 | 12 | # wlan0 exists only if the PCIe phy initialized 13 | # wlan0-ap never exists at this point (this is where we create it) 14 | if [ -e /sys/class/net/wlan0 ]; then 15 | # If the 3dr config file does not exist, or if it does and ApEnable is True, 16 | # set up the wlan0-ap interface 17 | if [ ! -f $SOLO_CONF ] || isEnabled $SOLO_CONF ApEnable; then 18 | echo -n "Initializing $DESC: " 19 | iw phy phy0 interface add $NAME type __ap 20 | ip link set dev $NAME address `/usr/bin/getmaclocal.py wlan0` 21 | echo "$NAME." 22 | fi 23 | else 24 | echo "wlan0 does not exist" 25 | fi 26 | -------------------------------------------------------------------------------- /net/usr/bin/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /net/usr/bin/clock.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Python interface into the posix clock functions 4 | # clock_gettime(), clock_settime() 5 | # 6 | # Motivation is to get access to CLOCK_MONOTONIC, so flight code can not care 7 | # about jumps in system time (in which case CLOCK_REALTIME and python's 8 | # datetime jump). 9 | 10 | import ctypes 11 | import os 12 | 13 | CLOCK_REALTIME = 0 14 | CLOCK_MONOTONIC = 1 15 | CLOCK_PROCESS_CPUTIME_ID = 2 16 | CLOCK_THREAD_CPUTIME_ID = 3 17 | CLOCK_MONOTONIC_RAW = 4 18 | CLOCK_REALTIME_COARSE = 5 19 | CLOCK_MONOTONIC_COARSE = 6 20 | CLOCK_BOOTTIME = 7 21 | CLOCK_REALTIME_ALARM = 8 22 | CLOCK_BOOTTIME_ALARM = 9 23 | 24 | class timespec(ctypes.Structure): 25 | _fields_ = [ 26 | ("tv_sec", ctypes.c_long), 27 | ("tv_nsec", ctypes.c_long) 28 | ] 29 | 30 | librt = ctypes.CDLL('librt.so.1', use_errno=True) 31 | 32 | clock_gettime = librt.clock_gettime 33 | clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)] 34 | 35 | clock_settime = librt.clock_settime 36 | clock_settime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)] 37 | 38 | def gettime(clock_id): 39 | t = timespec() 40 | if clock_gettime(clock_id, ctypes.pointer(t)) != 0: 41 | errno_ = ctypes.get_errno() 42 | raise OSError(errno_, os.strerror(errno_)) 43 | return t 44 | 45 | def gettime_us(clock_id): 46 | t = gettime(clock_id) 47 | return long(t.tv_sec * 1000000 + (t.tv_nsec + 500) / 1000) 48 | 49 | def settime(clock_id, t): 50 | if clock_settime(clock_id, ctypes.pointer(t)) != 0: 51 | errno_ = ctypes.get_errno() 52 | raise OSError(errno_, os.strerror(errno_)) 53 | 54 | def settime_us(clock_id, us): 55 | t = timespec(us/1000000, (us%1000000) * 1000) 56 | if clock_settime(clock_id, ctypes.pointer(t)) != 0: 57 | errno_ = ctypes.get_errno() 58 | raise OSError(errno_, os.strerror(errno_)) 59 | 60 | def test(do_set): 61 | rt = gettime(CLOCK_REALTIME) 62 | print "REALTIME: %10d.%09d" % (rt.tv_sec, rt.tv_nsec) 63 | mt = gettime(CLOCK_MONOTONIC) 64 | print "MONOTONIC: %10d.%09d" % (mt.tv_sec, mt.tv_nsec) 65 | if do_set: 66 | # WARNING: this sets the time to zero (1/1/1970) 67 | print "set time..." 68 | os.system("date --set=\"@0\"") 69 | rt = gettime(CLOCK_REALTIME) 70 | print "REALTIME: %10d.%09d" % (rt.tv_sec, rt.tv_nsec) 71 | mt = gettime(CLOCK_MONOTONIC) 72 | print "MONOTONIC: %10d.%09d" % (mt.tv_sec, mt.tv_nsec) 73 | 74 | if __name__ == "__main__": 75 | test(False) # True will set your system time to zero 76 | -------------------------------------------------------------------------------- /net/usr/bin/getmaclocal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import ip 5 | 6 | if len(sys.argv) < 2: 7 | print 'Usage: ' + sys.argv[0] + ' ' 8 | sys.exit(1) 9 | 10 | oldMac = ip.getMac(sys.argv[1]) 11 | if oldMac is None: 12 | print 'ERROR getting MAC address for ' + sys.argv[1] 13 | sys.exit(1) 14 | 15 | newMac = ip.macSetLocal(oldMac) 16 | if newMac is None: 17 | print 'ERROR getting local MAC address for ' + oldMac 18 | sys.exit(1) 19 | 20 | print newMac 21 | 22 | sys.exit(0) 23 | -------------------------------------------------------------------------------- /net/usr/bin/ip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | import subprocess 5 | 6 | 7 | # ip expected output: 8 | # 9 | # $ ip link 10 | # 1: lo: mtu 65536 qdisc noqueue 11 | # link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 12 | # 2: sit0: mtu 1480 qdisc noop 13 | # link/sit 0.0.0.0 brd 0.0.0.0 14 | # 3: wlan0: mtu 1500 qdisc mq qlen 1000 15 | # link/ether 00:02:60:51:90:06 brd ff:ff:ff:ff:ff:ff 16 | 17 | def getMac(ifName): 18 | try: 19 | iwOut = subprocess.check_output(['ip', 'link'], stderr=subprocess.STDOUT) 20 | except: 21 | return None 22 | m = re.search('^[0-9]+: ' + ifName + ': .*\n +link/[a-z]+ ([0-9a-f:]+) brd', iwOut, re.M) 23 | if m: 24 | return m.group(1) 25 | return None 26 | 27 | 28 | # Set the 02:00:00:00:00:00 bit in a MAC 29 | # The purpose of this is to set the "locally administered" bit in a MAC 30 | # (see http://en.wikipedia.org/wiki/MAC_address). The purpose of that is to 31 | # generate a second MAC that we can use for simultaneous AP/STATION support 32 | # for SoloLink. We handle the case where that bit is already set; it is not 33 | # expected to be set, but if it is, we would rather clear it than fail. 34 | 35 | def macSetLocal(mac): 36 | if len(mac) < 2: 37 | return None 38 | oldNibble = mac[1] 39 | # 0->2, 1->3, 4->6, etc. 40 | if oldNibble == '0': newNibble = '2' 41 | elif oldNibble == '1': newNibble = '3' 42 | elif oldNibble == '2': newNibble = '0' 43 | elif oldNibble == '3': newNibble = '1' 44 | elif oldNibble == '4': newNibble = '6' 45 | elif oldNibble == '5': newNibble = '7' 46 | elif oldNibble == '6': newNibble = '4' 47 | elif oldNibble == '7': newNibble = '5' 48 | elif oldNibble == '8': newNibble = 'a' 49 | elif oldNibble == '9': newNibble = 'b' 50 | elif oldNibble == 'a': newNibble = '8' 51 | elif oldNibble == 'b': newNibble = '9' 52 | elif oldNibble == 'c': newNibble = 'e' 53 | elif oldNibble == 'd': newNibble = 'f' 54 | elif oldNibble == 'e': newNibble = 'c' 55 | elif oldNibble == 'f': newNibble = 'd' 56 | else: 57 | return None 58 | return mac[0:1] + newNibble + mac[2:] 59 | 60 | 61 | # Return last three bytes of MAC as a string 62 | def mac3(ifname): 63 | mac = getMac(ifname) 64 | if len(mac) != 17: 65 | return "" 66 | return mac[9:11] + mac[12:14] + mac[15:17] 67 | 68 | 69 | if __name__ == "__main__": 70 | from optparse import OptionParser 71 | parser = OptionParser('ip.py [options]') 72 | parser.add_option('-3', '--mac3', dest='mac3_ifname', type='string', 73 | default=None, 74 | help='return last three bytes of interface\'s MAC') 75 | (opts, args) = parser.parse_args() 76 | if opts.mac3_ifname is not None: 77 | print mac3(opts.mac3_ifname) 78 | -------------------------------------------------------------------------------- /net/usr/bin/rc_cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import socket 5 | import threading 6 | from sololink import rc_pkt 7 | 8 | def in_thread(sock): 9 | while True: 10 | pkt = sock.recv(1000) 11 | if len(pkt) == rc_pkt.LENGTH: 12 | # assume it's RC 13 | timestamp, sequence, channels = rc_pkt.unpack(pkt) 14 | pkt = "%d %d %d %d %d %d %d %d %d %d" % \ 15 | (timestamp, sequence, 16 | channels[0], channels[1], channels[2], channels[3], 17 | channels[4], channels[5], channels[6], channels[7]) 18 | print pkt 19 | 20 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) 21 | sock.bind("/tmp/rc_cli." + str(os.getpid())) 22 | 23 | in_id = threading.Thread(target=in_thread, args=(sock,)) 24 | in_id.daemon = True 25 | in_id.start() 26 | 27 | while True: 28 | s = raw_input() 29 | sock.sendto(s, "/run/rc_uplink_cmd") 30 | -------------------------------------------------------------------------------- /pair/ifconfig.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | import subprocess 4 | 5 | 6 | def ip_mask(ifname): 7 | """get IP address and netmask for an interface if it has them 8 | 9 | The return is a tuple containing the address and netmask as strings. If 10 | either cannot be determined, None is returned in its place. If there is an 11 | error running the ifconfig command, None is returned instead of the tuple. 12 | 13 | Example: 14 | get_ip_mask("wlan0") 15 | normally returns something like: 16 | ("10.1.1.100", "255.255.255.0") 17 | but could return something like: 18 | ("10.1.1.100", None) 19 | """ 20 | 21 | try: 22 | out = subprocess.check_output(["ifconfig", ifname]) 23 | except: 24 | return None 25 | 26 | m = re.search("inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)", out) 27 | if not m: 28 | return None 29 | ip = m.group(1) 30 | 31 | m = re.search("Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)", out) 32 | if not m: 33 | return None 34 | mask = m.group(1) 35 | 36 | return (ip, mask) 37 | -------------------------------------------------------------------------------- /pair/ip_util.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import re 4 | 5 | 6 | dhcp_lease_file = "/var/lib/misc/dnsmasq.leases" 7 | 8 | 9 | def get_ip_mac(ip): 10 | """get MAC from IP 11 | 12 | ARP table is in /proc/net/arp: 13 | IP address HW type Flags HW address Mask Device 14 | 10.1.1.101 0x1 0x2 e8:2a:ea:50:5f:c8 * wlan0-ap 15 | 10.1.1.100 0x1 0x2 00:02:60:02:70:28 * wlan0-ap 16 | 17 | Returns None if IP is not in arp table. 18 | """ 19 | fn = "/proc/net/arp" 20 | try: 21 | f = open(fn) 22 | except: 23 | return None 24 | for line in f: 25 | m = re.match("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*?(\ 26 | [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:\ 27 | [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F])", line) 28 | if m: 29 | if m.group(1) == ip: 30 | return m.group(2) 31 | return None 32 | 33 | 34 | def clear_dhcp_lease(client_mac): 35 | new_lease_file = dhcp_lease_file + ".new" 36 | os.system("grep -i -v %s %s > %s" % \ 37 | (str(client_mac), dhcp_lease_file, new_lease_file)) 38 | os.rename(new_lease_file, dhcp_lease_file) 39 | os.system("/etc/init.d/dnsmasq restart") 40 | -------------------------------------------------------------------------------- /pair/pair.py: -------------------------------------------------------------------------------- 1 | 2 | # Definitions shared between client and server connection modules 3 | 4 | # Messages/commands used in connection process 5 | 6 | # Network messages are all 68 bytes: 7 | # start size description 8 | # 0 1 CMD_* 9 | # 1 1 SYS_* 10 | # 2 1 cmd_data 11 | # 3 1 locked 12 | # 4 32 sololink version 13 | # 36 32 firmware version (artoo or pixhawk) 14 | # 68 message length 15 | 16 | # Messages/commands 17 | CMD_CONN_REQ = 1 # client sends to request connection 18 | CMD_CONN_ACK = 2 # Received to ack a connection request 19 | CMD_USER_RSP = 3 # Internal; user response to connection request 20 | CMD_TIMEOUT = 4 # Timeout waiting for next message 21 | 22 | # return name for command 23 | def cmd_name(cmd): 24 | if cmd == CMD_CONN_REQ: return "CMD_CONN_REQ" 25 | elif cmd == CMD_CONN_ACK: return "CMD_CONN_ACK" 26 | elif cmd == CMD_USER_RSP: return "CMD_USER_RSP" 27 | elif cmd == CMD_TIMEOUT: return "CMD_TIMEOUT" 28 | else: return "CMD_UNKNOWN" 29 | 30 | # System types that may use the connection protocol 31 | SYS_CONTROLLER = 1 # 32 | SYS_SOLO = 2 # 33 | 34 | # return name for system type 35 | def sys_name(sys): 36 | if sys == SYS_CONTROLLER: return "SYS_CONTROLLER" 37 | elif sys == SYS_SOLO: return "SYS_SOLO" 38 | elif sys == SYS_APP: return "SYS_APP" 39 | else: return "SYS_UNKNOWN" 40 | 41 | # 'locked' byte in connect_request message 42 | DATA_LOCKED = 1 # sender is locked 43 | 44 | # connected state moves from NO to PEND to YES 45 | # network state moves from PEND to either NO or YES 46 | NO = 1 47 | PEND = 2 48 | YES = 3 49 | 50 | # all network messages are this long 51 | CONN_MSG_LEN = 68 52 | -------------------------------------------------------------------------------- /pair/pair_button.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Run this to simulate pressing the pair button on Solo. 4 | 5 | import struct 6 | import sys 7 | 8 | button_filename = "/dev/input/event0" 9 | button_error = False 10 | button_file = None 11 | 12 | # event is: 13 | # struct input_event { 14 | # struct timeval time; 15 | # unsigned short type; 16 | # unsigned short code; 17 | # unsigned int value; 18 | # }; 19 | # time: 8 bytes, not used here 20 | # type: EV_SYN=0x0000, EV_KEY=0x0001 21 | # code: KEY_WPS_BUTTON=0x0211 22 | # value: 1 on push, 0 on release 23 | # Fields are little endian. 24 | # 25 | # button push: 26 | # xx xx xx xx xx xx xx xx 01 00 11 02 01 00 00 00 27 | # type=0x0001 code=0x0211 value=0x00000001 28 | # xx xx xx xx xx xx xx xx 00 00 00 00 00 00 00 00 29 | # type=0x0000 code=0x0000 value=0x00000000 30 | # 31 | # button release: 32 | # xx xx xx xx xx xx xx xx 01 00 11 02 00 00 00 00 33 | # type=0x0001 code=0x0211 value=0x00000000 34 | # xx xx xx xx xx xx xx xx 00 00 00 00 00 00 00 00 35 | # type=0x0000 code=0x0000 value=0x00000000 36 | 37 | try: 38 | f = open(button_filename, "w") 39 | except: 40 | print "can't open %s for writing" % button_filename 41 | sys.exit(1) 42 | 43 | evt = struct.pack("@QHHi", 0, 0x0001, 0x0211, 1) 44 | f.write(evt) 45 | 46 | evt = struct.pack("@QHHi", 0, 0, 0, 0) 47 | f.write(evt) 48 | 49 | evt = struct.pack("@QHHi", 0, 0x0001, 0x0211, 0) 50 | f.write(evt) 51 | 52 | evt = struct.pack("@QHHi", 0, 0, 0, 0) 53 | f.write(evt) 54 | 55 | f.close() 56 | -------------------------------------------------------------------------------- /pair/pair_confirm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import socket 3 | import struct 4 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 5 | confirm = struct.pack("!BBB", 3, 1, 1) 6 | sock.sendto(confirm, ("127.0.0.1", 5501)) 7 | -------------------------------------------------------------------------------- /pair/runlevel.py: -------------------------------------------------------------------------------- 1 | 2 | import subprocess 3 | 4 | STANDBY = 3 5 | READY = 4 6 | MAINTENANCE = 5 7 | 8 | def set(level): 9 | subprocess.check_output(["init", str(level)]) 10 | 11 | def get(): 12 | r = subprocess.check_output(["runlevel"]) 13 | r = r.split() 14 | return int(r[1]) 15 | -------------------------------------------------------------------------------- /pair/wpa_supplicant_init: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # wpa_supplicant one-time initialization 4 | # 5 | # If Solo's name in wpa_supplicant.conf is the default, 6 | # change it to something unique. 7 | 8 | WPA_SUPPLICANT_CONF=/etc/wpa_supplicant.conf 9 | 10 | # Return true if Solo's name in wpa_supplicant.conf is still the default 11 | soloNameIsDefault() { 12 | grep -i -q "^device_name=Solo Default" $1 13 | } 14 | 15 | if soloNameIsDefault ${WPA_SUPPLICANT_CONF}; then 16 | soloname="Solo `/usr/bin/ip.py --mac3 wlan0`" 17 | sed -i "s/^device_name=Solo Default/device_name=${soloname}/" ${WPA_SUPPLICANT_CONF} 18 | md5sum ${WPA_SUPPLICANT_CONF} > ${WPA_SUPPLICANT_CONF}.md5 19 | fi 20 | -------------------------------------------------------------------------------- /pair/wps_confirm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This does the equivalent of: 4 | # hostapd_cli wps_pin any 5 | 6 | import socket 7 | 8 | print "wps_confirm.py starting" 9 | 10 | controlSock = "/var/run/hostapd/wlan0-ap" 11 | 12 | # Message sent to hostapd to confirm PIN pairing. The PIN embedded here must 13 | # match the PIN in Solo's script wps_request.py. It must be a valid WPS PIN; 14 | # use: 15 | # hostapd_cli wps_check_pin 16 | # wpa_cli wps_check_pin 17 | # to validate a pin, or: 18 | # wpa_cli wps_pin get 19 | # to get a new random pin. 20 | pinMessage = "WPS_PIN any 74015887" 21 | 22 | s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) 23 | 24 | try: 25 | s.sendto(pinMessage, controlSock) 26 | print "pin confirm sent to %s" % (controlSock, ) 27 | except: 28 | print "ERROR sending pin confirm to %s" % (controlSock, ) 29 | -------------------------------------------------------------------------------- /pair/wps_pair_msg.py: -------------------------------------------------------------------------------- 1 | 2 | import struct 3 | 4 | """ 5 | Pair Request/Confirm message sent between pairing and stm32 modules. 6 | 7 | Start 8 | Byte Size Description 9 | 0 4 ID (not used) 10 | 4 4 Length following (56) 11 | 8 4 Flags 12 | 12 20 MAC address, ASCII string (e.g. "02:1F:09:03:00:08") 13 | 32 32 Friendly name (e.g. "Solo Mynis") 14 | 64 (total packet length) 15 | """ 16 | 17 | MAC_LENGTH = 20 18 | NAME_LENGTH = 32 19 | BODY_LENGTH = 56 20 | TOTAL_LENGTH = 64 21 | 22 | FLAGS_REQUEST = 1 23 | FLAGS_CONFIRM = 2 24 | FLAGS_RESULT = 3 25 | 26 | fmt_string = " "Hel" 35 | # struct.pack("8s", "Hello") -> "Hello\0\0\0" 36 | # 37 | # struct.unpack will return a string of exactly the specified length, e.g. 38 | # struct.unpack("8s", "Hello\0\0\0") -> "Hello\0\0\0" 39 | 40 | def unpack(s): 41 | if len(s) != TOTAL_LENGTH: 42 | return None 43 | hdr_id, hdr_len, mac, name, flags = struct.unpack(fmt_string, s) 44 | mac = mac.strip("\0") 45 | name = name.strip("\0") 46 | return mac, name, flags 47 | 48 | def pack(mac, name, flags=0): 49 | # truncate MAC and Name if necessary so packed strings are \0 terminated 50 | if len(mac) > (MAC_LENGTH - 1): 51 | mac = mac[:(MAC_LENGTH - 1)] 52 | if len(name) > (NAME_LENGTH - 1): 53 | name = name[:(NAME_LENGTH - 1)] 54 | return struct.pack(fmt_string, MSG_ID, BODY_LENGTH, mac, name, flags) 55 | -------------------------------------------------------------------------------- /tools/3dcp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Helper script for scp'ing onto solo and artoo 3 | # 4 | # Syntax: 3dcp [ artoo | solo ] localfile remotepath 5 | # Note: Use absolute paths for sololink location 6 | # 7 | # Example usage: 8 | # 3dcp artoo test.py /home/root 9 | # 3dcp solo update.tar.gz /log/updates 10 | ################################################## 11 | 12 | CUR_SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 13 | 14 | USERNAME="root" 15 | TARGET="10.1.1.1" 16 | 17 | if [ "$1" == "solo" ] 18 | then 19 | TARGET="10.1.1.10" 20 | fi 21 | 22 | scp -i $CUR_SCRIPT_DIR/updater/updater_id_rsa $2 $USERNAME@$TARGET:$3 23 | -------------------------------------------------------------------------------- /tools/3dsh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Helper script for ssh'ing into solo and artoo 3 | # 4 | # Syntax: 3dsh [ solo | artoo ] 5 | # Note: Defaults to artoo without an argument 6 | ############################################### 7 | 8 | CUR_SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 9 | 10 | USERNAME="root" 11 | TARGET="10.1.1.1" 12 | 13 | if [ "$1" == "solo" ] 14 | then 15 | TARGET="10.1.1.10" 16 | fi 17 | 18 | ssh -i $CUR_SCRIPT_DIR/updater/updater_id_rsa $USERNAME@$TARGET 19 | -------------------------------------------------------------------------------- /tools/build/clang-format-run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os, sys, subprocess 4 | 5 | extensions = ( 6 | ".cpp", ".cxx", ".c++", ".cc", ".cp", 7 | ".c",".i", ".ii", ".h", ".h++", ".hpp", 8 | ".hxx", ".hh", ".inl", ".inc", ".ipp", 9 | ".ixx", ".txx", ".tpp", ".tcc", ".tpl" 10 | ) 11 | 12 | def find_clang_format(options): 13 | for c in options: 14 | try: 15 | v = subprocess.check_output([c, "--version"]) 16 | return c, v.strip() 17 | except: 18 | pass 19 | print "can't find clang-format in %s" % str(clang_format_list) 20 | sys.exit(1) 21 | 22 | # find the installed version of clang-format - we require at least 3.6 23 | clang_format_list = ("clang-format-3.6", "clang-format-3.7", "clang-format") 24 | clang_format, cf_version = find_clang_format(clang_format_list) 25 | 26 | # report differences unless "--apply" is given as argument 27 | do_apply = (len(sys.argv) >= 2) and (sys.argv[1] == "--apply") 28 | 29 | diff_files = [] 30 | 31 | for root, dirs, files in os.walk("."): 32 | if 'build' in dirs: 33 | dirs.remove('build') 34 | if 'install' in dirs: 35 | dirs.remove('install') 36 | for file in files: 37 | if file.endswith(extensions): 38 | fpath = os.path.join(root, file) 39 | if do_apply: 40 | subprocess.check_call([clang_format, "-i", "-style=file", fpath], stdout=subprocess.PIPE) 41 | else: 42 | # compare the output of clang-format with the current file, complain if there's a diff 43 | p1 = subprocess.Popen([clang_format, "-style=file", fpath], stdout=subprocess.PIPE) 44 | p2 = subprocess.Popen(["diff", "-u", fpath, "-"], stdin=p1.stdout, stdout=subprocess.PIPE) 45 | if p2.wait() != 0: 46 | diff_files.append(fpath) 47 | 48 | if len(diff_files) != 0: 49 | print cf_version, "reported differences for the following files:" 50 | for f in diff_files: 51 | print " ", f 52 | sys.exit(1) 53 | -------------------------------------------------------------------------------- /tools/build/sololink_new: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Uncomment one of these 4 | #machineList="imx6solo_3dr_artoo imx6solo_3dr imx6solo_3dr_analogtvin imx6solo_3dr_1080p" 5 | machineList="imx6solo_3dr_artoo imx6solo_3dr_1080p" 6 | 7 | if [ -z "${1}" ]; then 8 | bspBranch=imx-3.10.17-1.0.0_ga 9 | dateStr=`date +%Y%m%d_%H%M` 10 | buildName=sololink_$dateStr 11 | else 12 | bspBranch=${1} 13 | buildName=${1} 14 | #buildName=sololink_v${1} 15 | fi 16 | 17 | buildRoot=. 18 | 19 | mkdir $buildRoot/$buildName 20 | pushd $buildRoot/$buildName 21 | 22 | set -x 23 | 24 | ( 25 | 26 | echo "`date`: ${buildName}: start" 27 | 28 | repo init -u git@github.com:3drobotics/3dr-arm-yocto-bsp.git -b ${bspBranch} 29 | repo sync 30 | 31 | export EULA=1 32 | source ./setup-environment build 33 | 34 | if true; then 35 | 36 | # increase number of threads 37 | cpu_count=`grep -c ^processor /proc/cpuinfo` 38 | new_count=$(($cpu_count * 4)) 39 | echo "setting to ${new_count} threads" 40 | sed -i "s/^BB_NUMBER_THREADS = '[0-9]\+'/BB_NUMBER_THREADS = '${new_count}'/" conf/local.conf 41 | sed -i "s/^PARALLEL_MAKE = '-j [0-9]\+'/PARALLEL_MAKE = '-j ${new_count}'/" conf/local.conf 42 | 43 | fi 44 | 45 | if false; then 46 | 47 | # use local sources 48 | cat >> conf/local.conf <&1 | tee console.log 80 | 81 | set +x 82 | popd 83 | -------------------------------------------------------------------------------- /tools/logdownload/grabSoloLinkLogs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SCPARGS="-o StrictHostKeyChecking=no -i ../updater/updater_id_rsa" 4 | 5 | DATE=`date "+%Y-%m-%d-%H:%M:%S"` 6 | 7 | mkdir sololink-$DATE 8 | mkdir artoolink-$DATE 9 | 10 | ssh-keygen -R 10.1.1.1 &> /dev/null 11 | ssh-keygen -R 10.1.1.10 &> /dev/null 12 | 13 | scp $SCPARGS -r root@10.1.1.1:/log/* ./artoolink-$DATE/ 14 | scp $SCPARGS -r root@10.1.1.10:/log/* ./sololink-$DATE/ 15 | -------------------------------------------------------------------------------- /tools/scripts/px_usb_switch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import time 6 | import argparse 7 | 8 | SELECT_GPIO = "21" 9 | ENABLE_GPIO = "19" 10 | 11 | #GPIO direction set 12 | def setGPIODir(gpio, direction): 13 | dir_fd = open("/sys/class/gpio/gpio"+str(gpio)+"/direction", "w") 14 | dir_fd.write(direction) 15 | dir_fd.close() 16 | 17 | #Open the GPIO 18 | def openGPIO(gpio): 19 | #Check and see if the GPIO is already exported 20 | if not os.path.isdir("/sys/class/gpio/gpio"+str(gpio)): 21 | #otherwise export it 22 | exp_fd = open("/sys/class/gpio/export", "w") 23 | exp_fd.write(gpio) 24 | exp_fd.close() 25 | 26 | setGPIODir(gpio, "out"); 27 | 28 | def closeGPIO(gpio): 29 | unexp_fd = open("/sys/class/gpio/unexport", "w") 30 | unexp_fd.write(gpio) 31 | unexp_fd.close() 32 | 33 | def setGPIO(gpio, value): 34 | val_fd = open("/sys/class/gpio/gpio"+str(gpio)+"/value", "w") 35 | val_fd.write(value) 36 | val_fd.close() 37 | 38 | def openSetClose(gpio, value): 39 | openGPIO(gpio) 40 | setGPIO(gpio, value) 41 | closeGPIO(gpio) 42 | 43 | parser = argparse.ArgumentParser() 44 | parser.add_argument("state", help='enable [1] or disable [0] Pixhawk USB') 45 | args = parser.parse_args() 46 | 47 | if args.state == '1': 48 | print("Enabling PH2 USB") 49 | openSetClose(SELECT_GPIO, "1") 50 | openSetClose(ENABLE_GPIO, "0") 51 | else: 52 | print("Disabling PH2 USB") 53 | openSetClose(SELECT_GPIO, "0") 54 | openSetClose(ENABLE_GPIO, "1") 55 | -------------------------------------------------------------------------------- /tools/updater/.gitignore: -------------------------------------------------------------------------------- 1 | *.tar.* -------------------------------------------------------------------------------- /tools/updater/fetchLatest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Given a project directory (where "build" normally is), copy the latest 4 | # update images from: 5 | # build/tmp*/deploy/images/imx6solo_3dr/3dr-solo*.tar.gz 6 | # build/tmp*/deploy/images/imx6solo_3dr_artoo/3dr-controller*.tar.gz 7 | # renaming them in the copy with the supplied version number, e.g. 8 | # controller_x.y.z.tar.gz 9 | # solo_x.y.z.tar.gz 10 | # 11 | # $1 is the project directory 12 | # $2 is the version (x.y.z) 13 | 14 | if [ $# -eq 0 ]; then 15 | echo "Usage: $0 " 16 | echo " where the images are in /build/tmp*/deploy/images" 17 | exit 18 | fi 19 | 20 | if [ -z "${2}" ]; then 21 | version=`date +%Y%m%d` 22 | else 23 | version=${2} 24 | fi 25 | 26 | image_dir=$1/build/tmp*/deploy/images 27 | 28 | get_image() { 29 | # $1 is solo or controller 30 | # $2 is link_name 31 | # $3 is version 32 | if [ -e ${2} ]; then 33 | full_path=`readlink ${2}` 34 | src_name=`basename ${full_path}` 35 | dst_name=${1}_${3}.tar.gz 36 | echo "copying ${src_name} -> ${dst_name}" 37 | cp ${full_path} ${dst_name} 38 | cp ${full_path}.md5 ${dst_name}.md5 39 | sed -i "s/${src_name}/${dst_name}/g" ${dst_name}.md5 40 | else 41 | echo "${2} not found" 42 | fi 43 | } 44 | 45 | get_image solo ${image_dir}/imx6solo_3dr_1080p/3dr-solo-test.tar.gz ${version} 46 | get_image controller ${image_dir}/imx6solo_3dr_artoo/3dr-controller-test.tar.gz ${version} 47 | -------------------------------------------------------------------------------- /tools/updater/makeGolden.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #This script takes an updated image and pushes it 4 | #on to the GOLDEN partition of the SD card, creating a 5 | #new golden image. This should only be used for 6 | #development and production. 7 | 8 | #Make sure we're running on the update partition 9 | BOOTPART=`grep 'boot' /proc/mounts | awk '{print $1}'` 10 | 11 | if [ $BOOTPART == "/dev/mmcblk0p1" ]; then 12 | echo "Already on golden partition" 13 | exit 14 | else 15 | echo "Making the update partition the golden partition" 16 | fi; 17 | 18 | echo "Unmounting the golden partition" 19 | umount /dev/mmcblk0p1 20 | 21 | echo "Creating the golden partition filesystem" 22 | mkfs.vfat /dev/mmcblk0p1 -n GOLDEN 23 | 24 | echo "Mounting GOLDEN and copying files from LATEST" 25 | mkdir -p golden 26 | mount /dev/mmcblk0p1 golden 27 | cp -r /mnt/boot/* golden/ 28 | umount golden 29 | 30 | echo "All done! Run a factory reset if you'd like." 31 | 32 | -------------------------------------------------------------------------------- /tools/updater/unpair: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ssh_args="-o StrictHostKeyChecking=no -i ./updater_id_rsa" 4 | 5 | 6 | solo_ip=10.1.1.10 7 | 8 | echo -n "Unpairing Solo..." 9 | while ! ping -c1 -W1 $solo_ip &> /dev/null; do echo -n "."; done 10 | 11 | sh-keygen -R $solo_ip &> /dev/null 12 | 13 | ssh $ssh_args root@$solo_ip 'cp /mnt/rootfs.ro/etc/wpa_supplicant.orig /etc/wpa_supplicant.conf; md5sum /etc/wpa_supplicant.conf > /etc/wpa_supplicant.conf.md5; sync; reboot' 14 | 15 | echo "OK" 16 | 17 | 18 | artoo_ip=10.1.1.1 19 | 20 | echo -n "Unpairing Artoo..." 21 | while ! ping -c1 -W1 $artoo_ip &> /dev/null; do echo -n "."; done 22 | 23 | sh-keygen -R $artoo_ip &> /dev/null 24 | 25 | ssh $ssh_args root@$artoo_ip 'rm -f /log/3dr-pairing.conf; sync; reboot' 26 | 27 | echo "OK" 28 | -------------------------------------------------------------------------------- /wifi/Makefile: -------------------------------------------------------------------------------- 1 | # To cross compile: 2 | # 3 | # Set up as usual for bitbake: 4 | # $ . setup-environment build 5 | # 6 | # In the build directory: 7 | # $ bitbake meta-ide-support 8 | # $ . tmp/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi 9 | # 10 | # Now a make in this directory should work. 11 | 12 | VPATH = ../flightcode/util 13 | 14 | INCROOT = $(OECORE_TARGET_SYSROOT)/usr/include 15 | CFLAGS += -Wall 16 | 17 | BIN1 = wifistats 18 | BIN2 = survey_dump 19 | 20 | all: $(BIN1) $(BIN2) 21 | 22 | wifistats: CFLAGS += -I../flightcode/util 23 | wifistats: wifistats.o util.o 24 | $(LINK.c) -o wifistats wifistats.o util.o 25 | 26 | survey_dump: CFLAGS += -I$(INCROOT)/libnl3 27 | survey_dump: LDLIBS += -lnl-3 -lnl-genl-3 28 | 29 | clean: 30 | $(RM) *.o *~ $(BIN1) $(BIN2) 31 | 32 | .PHONY: all clean 33 | -------------------------------------------------------------------------------- /wifi/logRCUp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | XMITFILE=/sys/kernel/debug/ieee80211/phy0/ath9k/xmit 4 | 5 | LASTBYTES=0 6 | while [ True ]; do 7 | 8 | #Scrape the number of transmitted bytes 9 | 10 | #Needs to handle output like this (colums run together): 11 | #TX-Pkts-All: 4508487 0 784093 369638 12 | #TX-Bytes-All: 1050712988 01076297731 40691534 13 | #HW-put-tx-buf: 1050315 0 318996 368833 14 | # NF is the number of fields (normally 5, 4 when they run together 15 | # $NF is the last field 16 | 17 | BYTES=`cat $XMITFILE | grep 'TX-Bytes-All' | awk '{ print $NF }'` 18 | 19 | #So we don't put out bogus data 20 | if [ $LASTBYTES -ne 0 ]; then 21 | 22 | #Calculate the delta 23 | DELTA=$((BYTES-LASTBYTES)) 24 | 25 | logger -t wifi -p local2.info -- "${DELTA}" 26 | 27 | fi 28 | 29 | LASTBYTES=$BYTES 30 | 31 | #Log every second 32 | sleep 1 33 | 34 | done 35 | -------------------------------------------------------------------------------- /wifi/survey_log: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | logfile=/log/3dr-solo.log 4 | 5 | # This is run once from inittab when entering run level 3. 6 | # WiFi has not quite finished initializing by then, so wait a bit. 7 | # Running on ifup does not work; wifi is never finished scanning at that point. 8 | sleep 10 9 | 10 | echo "" >> ${logfile} 11 | 12 | grep ^acs_num_scans= /etc/hostapd.conf >> ${logfile} 13 | 14 | survey_dump >> ${logfile} 15 | 16 | echo "" >> ${logfile} 17 | --------------------------------------------------------------------------------