diff --git a/CHANGELOG.md b/CHANGELOG.md index 1918483f..13d5fa31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ Please add a note of your changes below this heading if you make a Pull Request. * Some Encoder settings have been made read-only * Cleaned up VSCode C/C++ Configuration settings on Windows with recursive includePath * Now compiling with C++17 +* Fixed a firmware hang that could occur from unlikely but possible user input + # Releases ## [0.4.11] - 2019-07-25 ### Added diff --git a/Firmware/MotorControl/axis.cpp b/Firmware/MotorControl/axis.cpp index 5635c70c..0e6f64dc 100644 --- a/Firmware/MotorControl/axis.cpp +++ b/Firmware/MotorControl/axis.cpp @@ -338,7 +338,7 @@ bool Axis::run_closed_loop_control_loop() { return true; }); - set_step_dir_active(false); + set_step_dir_active(config_.enable_step_dir && config_.step_dir_always_on); return check_for_errors(); } @@ -428,6 +428,7 @@ bool Axis::run_idle_loop() { // run_control_loop ignores missed modulation timing updates // if and only if we're in AXIS_STATE_IDLE safety_critical_disarm_motor_pwm(motor_); + set_step_dir_active(config_.enable_step_dir && config_.step_dir_always_on); run_control_loop([this]() { return true; }); diff --git a/Firmware/MotorControl/axis.hpp b/Firmware/MotorControl/axis.hpp index 50e72d00..9f99f33a 100644 --- a/Firmware/MotorControl/axis.hpp +++ b/Firmware/MotorControl/axis.hpp @@ -68,8 +68,14 @@ public: bool startup_closed_loop_control = false; //trap_.config_.vel_limit, axis_->trap_.config_.accel_limit, axis_->trap_.config_.decel_limit); - traj_start_loop_count_ = axis_->loop_counter_; + axis_->trap_.t_ = 0.0f; trajectory_done_ = false; } @@ -160,7 +160,7 @@ bool Controller::update(float* current_setpoint_output) { float step = std::clamp(full_step, -max_step_size, max_step_size); vel_setpoint_ += step; - current_setpoint_ = step / current_meas_period * config_.inertia; + current_setpoint_ = (step / current_meas_period) * config_.inertia; } break; case INPUT_MODE_CURRENT_RAMP: { float max_step_size = std::abs(current_meas_period * config_.current_ramp_rate); @@ -198,10 +198,8 @@ bool Controller::update(float* current_setpoint_output) { // Avoid updating uninitialized trajectory if (trajectory_done_) break; - // Note: uint32_t loop count delta is OK across overflow - // Beware of negative deltas, as they will not be well behaved due to uint! - float t = (axis_->loop_counter_ - traj_start_loop_count_) * current_meas_period; - if (t > axis_->trap_.Tf_) { + + if (axis_->trap_.t_ > axis_->trap_.Tf_) { // Drop into position control mode when done to avoid problems on loop counter delta overflow config_.control_mode = CTRL_MODE_POSITION_CONTROL; pos_setpoint_ = input_pos_; @@ -209,10 +207,11 @@ bool Controller::update(float* current_setpoint_output) { current_setpoint_ = 0.0f; trajectory_done_ = true; } else { - TrapezoidalTrajectory::Step_t traj_step = axis_->trap_.eval(t); + TrapezoidalTrajectory::Step_t traj_step = axis_->trap_.eval(axis_->trap_.t_); pos_setpoint_ = traj_step.Y; vel_setpoint_ = traj_step.Yd; current_setpoint_ = traj_step.Ydd * config_.inertia; + axis_->trap_.t_ += current_meas_period; } anticogging_pos = pos_setpoint_; // FF the position setpoint instead of the pos_estimate } break; diff --git a/Firmware/MotorControl/controller.hpp b/Firmware/MotorControl/controller.hpp index afbb4edd..56a60020 100644 --- a/Firmware/MotorControl/controller.hpp +++ b/Firmware/MotorControl/controller.hpp @@ -117,7 +117,6 @@ public: bool input_pos_updated_ = false; - uint32_t traj_start_loop_count_ = 0; bool trajectory_done_ = true; bool anticogging_valid_ = false; diff --git a/Firmware/MotorControl/trapTraj.hpp b/Firmware/MotorControl/trapTraj.hpp index 6c343c42..fd142da5 100644 --- a/Firmware/MotorControl/trapTraj.hpp +++ b/Firmware/MotorControl/trapTraj.hpp @@ -47,6 +47,8 @@ public: float Tf_; float yAccel_; + + float t_; }; #endif \ No newline at end of file diff --git a/Firmware/MotorControl/utils.hpp b/Firmware/MotorControl/utils.hpp index 574aa800..224f3716 100644 --- a/Firmware/MotorControl/utils.hpp +++ b/Firmware/MotorControl/utils.hpp @@ -69,18 +69,6 @@ static const float one_by_sqrt3 = 0.57735026919f; static const float two_by_sqrt3 = 1.15470053838f; static const float sqrt3_by_2 = 0.86602540378f; -//beware of inserting large values! -static inline float wrap_pm(float x, float pm_range) { - while (x >= pm_range) x -= (2.0f * pm_range); - while (x < -pm_range) x += (2.0f * pm_range); - return x; -} - -//beware of inserting large angles! -static inline float wrap_pm_pi(float theta) { - return wrap_pm(theta, M_PI); -} - // like fmodf, but always positive static inline float fmodf_pos(float x, float y) { float out = fmodf(x, y); @@ -89,6 +77,20 @@ static inline float fmodf_pos(float x, float y) { return out; } +/** + * @brief Similar to modulo operator, except that the output range is centered + * around zero. + * The returned value is always in the range [-pm_range, pm_range). + */ +static inline float wrap_pm(float x, float pm_range) { + return fmodf_pos(x + pm_range, 2.0f * pm_range) - pm_range; +} + +//beware of inserting large angles! +static inline float wrap_pm_pi(float theta) { + return wrap_pm(theta, M_PI); +} + // Compute rising edge timings (0.0 - 1.0) as a function of alpha-beta // as per the magnitude invariant clarke transform // The magnitude of the alpha-beta vector may not be larger than sqrt(3)/2 diff --git a/docs/ascii-protocol.md b/docs/ascii-protocol.md index a0757e2f..5e1dc236 100644 --- a/docs/ascii-protocol.md +++ b/docs/ascii-protocol.md @@ -131,7 +131,7 @@ Not all parameters can be accessed via the ASCII protocol but at least all param ``` * `property` name of the property, as seen in ODrive Tool * `value` text representation of the value to be written - * Example: `w axis0.controller.pos_setpoint -123.456` + * Example: `w axis0.controller.input_pos -123.456` #### System commands: * `ss` - Save config diff --git a/docs/commands.md b/docs/commands.md index 2d26586a..ae5e9e8f 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -60,6 +60,21 @@ Possible values are: * `CTRL_MODE_CURRENT_CONTROL` * `CTRL_MODE_VOLTAGE_CONTROL` - this one is not normally used. +### Input Mode +The default input mode is `INPUT_MODE_PASSTHROUGH`. +Modes can be selected by changing `.controller.config.input_mode`. +Possible values are: +* `INPUT_MODE_INACTIVE` +* `INPUT_MODE_PASSTHROUGH` +* `INPUT_MODE_VEL_RAMP` +* `INPUT_MODE_POS_FILTER` +* `INPUT_MODE_MIX_CHANNELS` +* `INPUT_MODE_TRAP_TRAJ` +* `INPUT_MODE_CURRENT_RAMP` +* `INPUT_MODE_MIRROR` + +For more information, see [input_modes](input_modes.md). + # Control Commands * `.controller.input_pos = ` * `.controller.input_vel = ` @@ -96,7 +111,7 @@ All variables that are part of a `[...].config` object can be saved to non-volat The ODrive can run without encoder/hall feedback, but there is a minimum speed, usually around a few hunderd RPM. However the units of this mode is different from when using an encoder. Velocities are not measured in counts/s, instead it is electrical rad/s. This also applies to the gains. For example, `vel_gain` is in units of `A / (rad/s)` instead of `A / (count/s)`. -To give an example, suppose you have a motor with 7 pole pairs, and you want to spin it at 3000 RPM. Then you would set the `vel_setpoint` to `3000 * 2*pi/60 * 7 = 2199 rad/s electrical`. +To give an example, suppose you have a motor with 7 pole pairs, and you want to spin it at 3000 RPM. Then you would set the `input_vel` to `3000 * 2*pi/60 * 7 = 2199 rad/s electrical`. Below are some suggested starting parameters that you can use. Note that you _must_ set the `pm_flux_linkage` correctly for sensorless mode to work. @@ -104,7 +119,7 @@ Below are some suggested starting parameters that you can use. Note that you _mu odrv0.axis0.controller.config.vel_gain = 0.01 odrv0.axis0.controller.config.vel_integrator_gain = 0.05 odrv0.axis0.controller.config.control_mode = 2 -odrv0.axis0.controller.vel_setpoint = 400 +odrv0.axis0.controller.input_vel = 400 odrv0.axis0.motor.config.direction = 1 odrv0.axis0.sensorless_estimator.config.pm_flux_linkage = 5.51328895422 / ( * ) ``` diff --git a/docs/control.md b/docs/control.md index 8af90a91..267049fd 100644 --- a/docs/control.md +++ b/docs/control.md @@ -2,7 +2,7 @@ The motor controller is a cascaded style position, velocity and current control loop, as per the diagram below. When the control mode is set to position control, the whole loop runs. When running in velocity control mode, the position control part is removed and the velocity command is fed directly in to the second stage input. In current control mode, only the current controller is used. -![Cascaded pos vel I loops](https://github.com/madcowswe/ODrive/blob/master/docs/controller_with_ff.png?raw=true) +![Cascaded pos vel I loops](controller_with_ff.png) Each stage of the control loop is a variation on a [PID controller](https://en.wikipedia.org/wiki/PID_controller). A PID controller is a mathematical model that can be adapted to control a wide variety of systems. This flexibility is essential as it allows the ODrive to be used to control all kinds of mechanical systems. diff --git a/docs/encoders.md b/docs/encoders.md index cb038850..d0b60bdf 100644 --- a/docs/encoders.md +++ b/docs/encoders.md @@ -70,7 +70,7 @@ If calibration works, congratulations. Now try: * `.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL` -* `.controller.set_vel_setpoint(3000,0) ` +* `.controller.input_vel = 3000` let it loop a few times and then set: * `.requested_state = AXIS_STATE_IDLE` diff --git a/docs/getting-started.md b/docs/getting-started.md index df3a8ad9..146ed201 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -247,7 +247,7 @@ Let's get motor 0 up and running. The procedure for motor 1 is exactly the same, 2. Type `odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL` Enter. From now on the ODrive will try to hold the motor's position. If you try to turn it by hand, it will fight you gently. That is unless you bump up `odrv0.axis0.motor.config.current_lim`, in which case it will fight you more fiercely. If the motor begins to vibrate either immediately or after being disturbed you will need to [lower the controller gains](control.md). -3. Send the motor a new position setpoint. `odrv0.axis0.controller.pos_setpoint = 10000` Enter. The units are in encoder counts. +3. Send the motor a new position setpoint. `odrv0.axis0.controller.input_pos = 10000` Enter. The units are in encoder counts. 4. At this point you will probably want to [Properly tune](control.md) the motor controller in order to maximize system performance. ## Other control modes @@ -328,16 +328,16 @@ You can also execute a move with the [appropriate ascii command](ascii-protocol. To enable Circular position control, set `axis.controller.config.setpoints_in_cpr = True` This mode is useful for continuos incremental position movement. For example a robot rolling indefinitely, or an extruder motor or conveyor belt moving with controlled increments indefinitely. -In the regular position mode, the `pos_setpoint` would grow to a very large value and would lose precision due to floating point rounding. +In the regular position mode, the `input_pos` would grow to a very large value and would lose precision due to floating point rounding. -In this mode, the controller will try to track the position within only one turn of the motor. Specifically, `pos_setpoint` is expected in the range `[0, cpr-1]`, where `cpr` is the number of encoder counts in one revolution. If the `pos_setpoint` is incremented to outside this range (say via step/dir input), it is automatically wrapped around into the correct value. +In this mode, the controller will try to track the position within only one turn of the motor. Specifically, `input_pos` is expected in the range `[0, cpr-1]`, where `cpr` is the number of encoder counts in one revolution. If the `input_pos` is incremented to outside this range (say via step/dir input), it is automatically wrapped around into the correct value. Note that in this mode `encoder.pos_cpr` is used for feedback in stead of `encoder.pos_estimate`. If you try to increment the axis with a large step in one go that exceeds `cpr/2` steps, the motor will go to the same angle around the wrong way. This is also the case if there is a large disturbance. If you have an application where you would like to handle larger steps, you can use a virtual CPR that is an integer times larger than your encoder's actual CPR. Set `encoder.config.cpr = N * your_enc_cpr`, where N is some integer. Choose N to give you an appropriate circular space for your application. ### Velocity control Set `axis.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL`.
-You can now control the velocity with `axis.controller.vel_setpoint = 5000` [count/s]. +You can now control the velocity with `axis.controller.input_vel = 5000` [count/s]. ### Ramped velocity control Set `axis.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL`.
@@ -347,7 +347,7 @@ You can now control the velocity with `axis.controller.input_vel = 5000` [count/ ### Current control Set `axis.controller.config.control_mode = CTRL_MODE_CURRENT_CONTROL`.
-You can now control the current with `axis.controller.current_setpoint = 3` [A]. +You can now control the current with `axis.controller.input_current = 3` [A]. Note: If you exceed `vel_limit` in current control mode, the current is reduced. To disable this, set `axis.controller.enable_current_vel_limit = False`. diff --git a/docs/hoverboard.md b/docs/hoverboard.md index 730391fd..91b50764 100644 --- a/docs/hoverboard.md +++ b/docs/hoverboard.md @@ -112,9 +112,9 @@ The ODrive starts in idle (we will look at changing this later) so we can enable odrv0.save_configuration() odrv0.reboot() odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL -odrv0.axis0.controller.vel_setpoint = 120 +odrv0.axis0.controller.input_vel = 120 # Your motor should spin here -odrv0.axis0.controller.vel_setpoint = 0 +odrv0.axis0.controller.input_vel = 0 odrv0.axis0.requested_state = AXIS_STATE_IDLE ``` @@ -128,31 +128,31 @@ We also have to reboot to activate the PWM input. ```txt odrv0.config.gpio3_pwm_mapping.min = -200 odrv0.config.gpio3_pwm_mapping.max = 200 -odrv0.config.gpio3_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['vel_setpoint'] +odrv0.config.gpio3_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['input_vel'] odrv0.config.gpio4_pwm_mapping.min = -200 odrv0.config.gpio4_pwm_mapping.max = 200 -odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis1.controller._remote_attributes['vel_setpoint'] +odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis1.controller._remote_attributes['input_vel'] odrv0.save_configuration() odrv0.reboot() ``` -Now we can check that the sticks are writing to the velocity setpoint. Move the stick, print `vel_setpoint`, move to a different position, check again. +Now we can check that the sticks are writing to the velocity setpoint. Move the stick, print `input_vel`, move to a different position, check again. ```txt -In [1]: odrv0.axis1.controller.vel_setpoint +In [1]: odrv0.axis1.controller.input_vel Out[1]: 0.1904754638671875 -In [2]: odrv0.axis1.controller.vel_setpoint +In [2]: odrv0.axis1.controller.input_vel Out[2]: 0.1904754638671875 -In [3]: odrv0.axis1.controller.vel_setpoint +In [3]: odrv0.axis1.controller.input_vel Out[3]: 28.152389526367188 -In [4]: odrv0.axis1.controller.vel_setpoint +In [4]: odrv0.axis1.controller.input_vel Out[4]: 61.21905517578125 -In [5]: odrv0.axis1.controller.vel_setpoint +In [5]: odrv0.axis1.controller.input_vel Out[5]: -52.990474700927734 ``` diff --git a/docs/input_modes.md b/docs/input_modes.md new file mode 100644 index 00000000..32d7df86 --- /dev/null +++ b/docs/input_modes.md @@ -0,0 +1,113 @@ +# Input Modes +As of version ###, ODrive now intercepts the incoming commands and can apply filters to them. The old protocol values `pos_setpoint`, `vel_setpoint`, and `current_setpoint` are still used internally by the closed-loop cascade control, but the user cannot write to them directly. This allows us to condense the number of ways the ODrive accepts motion commands. The new commands are: + +* `.controller.config.input_mode` +* `.controller.input_pos` +* `.controller.input_vel` +* `.controller.input_current` + +The Input Modes currently valid are: +* `INPUT_MODE_INACTIVE` +* `INPUT_MODE_PASSTHROUGH` +* `INPUT_MODE_VEL_RAMP` +* `INPUT_MODE_POS_FILTER` +* `INPUT_MODE_MIX_CHANNELS` +* `INPUT_MODE_TRAP_TRAJ` +* `INPUT_MODE_CURRENT_RAMP` +* `INPUT_MODE_MIRROR` + +--- + +## INPUT_MODE_INACTIVE +Disable inputs. Setpoints retain their last value. + +## INPUT_MODE_PASSTHROUGH +Pass `input_xxx` through to `xxx_setpoint` directly. + +### Valid Inputs: +* `input_pos` +* `input_vel` +* `input_current` + +### Valid Control modes: +* `CTRL_MODE_VOLTAGE_CONTROL` +* `CTRL_MODE_CURRENT_CONTROL` +* `CTRL_MODE_VELOCITY_CONTROL` +* `CTRL_MODE_POSITION_CONTROL` + +## INPUT_MODE_VEL_RAMP +Ramps a velocity command from the current value to the target value. + +### Configuration Values: +* `.controller.config.vel_ramp_rate` [cpr/sec] +* `.controller.config.inertia` [A/(count/s^2))] + +### Valid inputs: +* `input_vel` + +### Valid Control Modes: +* `CTRL_MODE_VELOCITY_CONTROL` + +## INPUT_MODE_POS_FILTER +Implements a 2nd order position tracking filter. Inteded for use with step/dir interface, but can also be used with position-only commands. + +![POS Filter Response](secondOrderResponse.png) +Result of a step command from 1000 to 0 + +### Configuration Values: +* `.controller.config.input_filter_bandwidth` +* `.controller.config.inertia` + +### Valid inputs: +* `input_pos` + +### Valid Control modes: +* `CTRL_MODE_POSITION_CONTROL` + +## INPUT_MODE_MIX_CHANNELS +Not Implemented. + + +## INPUT_MODE_TRAP_TRAJ +Implementes an online trapezoidal trajectory planner. + +![Trapezoidal Planner Response](TrapTrajPosVel.png) + +### Configuration Values: +* `.trap_traj.config.vel_limit` +* `.trap_traj.config.accel_limit` +* `.trap_traj.config.decel_limit` +* `.controller.config.inertia` + +### Valid Inputs: +* `input_pos` + +### Valid Control Modes: +* `CTRL_MODE_POSITION_CONTROL` + +## INPUT_MODE_CURRENT_RAMP +Ramp a current command from the current value to the target value. + +### Configuration Values: +* `.controller.config.current_ramp_rate` + +### Valid Inputs: +* `input_current` + +### Valid Control Modes: +* `CTRL_MODE_CURRENT_CONTROL` + +## INPUT_MODE_MIRROR +Implements "electronic mirroring". This is like electronic camming, but you can only mirror exactly the movements of the other motor, according to a fixed ratio + +[![](http://img.youtube.com/vi/D4_vBtyVVzM/0.jpg)](http://www.youtube.com/watch?v=D4_vBtyVVzM "Example Mirroring Video") + +### Configuration Values +* `.controller.config.axis_to_mirror` +* `.controller.config.mirror_ratio` + +### Valid Inputs +* None. Inputs are taken directly from the other axis encoder estimates + +### Valid Control modes +* `CTRL_MODE_POSITION_CONTROL` diff --git a/docs/interfaces.md b/docs/interfaces.md index ca9db588..13dccec4 100644 --- a/docs/interfaces.md +++ b/docs/interfaces.md @@ -115,13 +115,13 @@ Some GPIO pins can be used for PWM input, if they are not allocated to other fun Any of the numerical parameters that are writable from the ODrive Tool can be hooked up to a PWM input. As an example, we'll configure GPIO4 to control the angle of axis 0. We want the axis to move within a range of -1500 to 1500 encoder counts. -1. Make sure you're able control the axis 0 angle by writing to `odrv0.axis0.controller.pos_setpoint`. If you need help with this follow the [getting started guide](getting-started.md). +1. Make sure you're able control the axis 0 angle by writing to `odrv0.axis0.controller.input_pos`. If you need help with this follow the [getting started guide](getting-started.md). 2. If you want to control your ODrive with the PWM input without using anything else to activate the ODrive, you can configure the ODrive such that axis 0 automatically goes operational at startup. See [here](commands.md#startup-procedure) for more information. 3. In ODrive Tool, configure the PWM input mapping ``` In [1]: odrv0.config.gpio4_pwm_mapping.min = -1500 In [2]: odrv0.config.gpio4_pwm_mapping.max = 1500 - In [3]: odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['pos_setpoint'] + In [3]: odrv0.config.gpio4_pwm_mapping.endpoint = odrv0.axis0.controller._remote_attributes['input_pos'] ``` Note: you can disable the input by setting `odrv0.config.gpio4_pwm_mapping.endpoint = None` 4. Save the configuration and reboot diff --git a/docs/test.md b/docs/test.md deleted file mode 100644 index 9daeafb9..00000000 --- a/docs/test.md +++ /dev/null @@ -1 +0,0 @@ -test diff --git a/tools/odrive/tests/analog_input_test.py b/tools/odrive/tests/analog_input_test.py new file mode 100644 index 00000000..d1f83774 --- /dev/null +++ b/tools/odrive/tests/analog_input_test.py @@ -0,0 +1,123 @@ + +import test_runner + +import time +import math +import os +import numpy as np + +from odrive.enums import errors +from test_runner import * + + +teensy_code_template = """ +void setup() { + analogWriteResolution(10); + // base clock of the PWM timer is 150MHz (on Teensy 4.0) + int freq = 150000000/1024; // ~146.5kHz PWM frequency + analogWriteFrequency({analog_out}, freq); + + // for filtering, assuming we have a 150 Ohm resistor, we need a capacitor of + // 1/(150000000/1024)*2*pi/150 = 2.85954744646751e-07 F, that's ~0.33uF + + //pinMode({lpf_enable}, OUTPUT); +} + +int i = 0; +void loop() { + i++; + i = i & 0x3ff; + if (digitalRead({analog_reset})) + i = 0; + analogWrite({analog_out}, i); + delay(1); +} +""" + + +class TestAnalogInput(): + """ + Verifies the Analog input. + + The Teensy generates a PWM signal with a duty cycle that follows a sawtooth signal + with a period of 1 second. The signal should be connected to the ODrive's + analog input through a low-pass-filter. + + ___ ___ + Teensy PWM ----|___|-------o---------|___|----- ODrive Analog Input + 150 Ohm | 150 Ohm + === + | 330nF + | + GND + + """ + + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + for odrive_gpio_num, odrive_gpio in [(2, odrive.gpio3), (3, odrive.gpio4)]: + analog_out_options = [] + lpf_gpio = [gpio for lpf in testrig.get_connected_components(odrive_gpio, LowPassFilterComponent) + for gpio in testrig.get_connected_components(lpf.en, LinuxGpioComponent)] + for teensy_gpio in testrig.get_connected_components(odrive_gpio, TeensyGpio): + teensy = teensy_gpio.parent + analog_reset_options = [] + for gpio in teensy.gpios: + for local_gpio in testrig.get_connected_components(gpio, LinuxGpioComponent): + analog_reset_options.append((gpio, local_gpio)) + analog_out_options.append((teensy, teensy_gpio, analog_reset_options)) + yield (odrive, lpf_gpio, odrive_gpio_num, analog_out_options) + + + def run_test(self, odrive: ODriveComponent, lpf_enable: LinuxGpioComponent, analog_in_num: int, teensy: TeensyComponent, teensy_analog_out: Component, teensy_analog_reset: Component, analog_reset_gpio: LinuxGpioComponent, logger: Logger): + code = teensy_code_template.replace("{analog_out}", str(teensy_analog_out.num)).replace("{analog_reset}", str(teensy_analog_reset.num)) #.replace("lpf_enable", str(lpf_enable.num)) + teensy.compile_and_program(code) + analog_reset_gpio.config(output=True) + analog_reset_gpio.write(True) + lpf_enable.config(output=True) + lpf_enable.write(False) + + logger.debug("Set up analog input...") + + min_val = -20000 + max_val = 20000 + period = 1.025 # period in teensy code is 1s, but due to tiny overhead it's a bit longer + + analog_mapping = [ + None, #odrive.handle.config.gpio1_analog_mapping, + None, #odrive.handle.config.gpio2_analog_mapping, + odrive.handle.config.gpio3_analog_mapping, + odrive.handle.config.gpio4_analog_mapping, + None, #odrive.handle.config.gpio5_analog_mapping, + ][analog_in_num] + + odrive.unuse_gpios() + analog_mapping.endpoint = odrive.handle.axis0.controller._remote_attributes['input_pos'] + analog_mapping.min = min_val + analog_mapping.max = max_val + odrive.save_config_and_reboot() + + + logger.debug("Recording log...") + data = [] + start = time.monotonic() + analog_reset_gpio.write(False) + while time.monotonic() - start < 5.0: + data.append(( + time.monotonic() - start, + odrive.handle.axis0.controller.input_pos + )) + + data = np.array(data) + + # Expect mean error to be at most 2% (of the full scale). + # Expect there to be less than 2% outliers, where an outlier is anything that is more than 5% (of full scale) away from the expected value. + full_range = abs(max_val - min_val) + slope, offset, fitted_curve = fit_sawtooth(data, min_val, max_val) + test_assert_eq(slope, (max_val - min_val) / period, accuracy=0.005) + test_curve_fit(data, fitted_curve, max_mean_err = full_range * 0.02, inlier_range = full_range * 0.05, max_outliers = len(data[:,0]) * 0.02) + + + +if __name__ == '__main__': + test_runner.run(TestAnalogInput()) diff --git a/tools/odrive/tests/calibration_test.py b/tools/odrive/tests/calibration_test.py index 5316f8d4..3cd60740 100644 --- a/tools/odrive/tests/calibration_test.py +++ b/tools/odrive/tests/calibration_test.py @@ -6,12 +6,9 @@ from math import pi import os from fibre.utils import Logger -from test_runner import AxisTestContext, MotorTestContext, EncoderTestContext, test_assert_eq, test_assert_no_error, request_state, program_teensy +from test_runner import * from odrive.enums import * -def modpm(val, range): - return ((val + (range / 2)) % range) - (range / 2) - class TestMotorCalibration(): """ @@ -19,14 +16,19 @@ class TestMotorCalibration(): and checks if the measurements match the expectation. """ - def is_compatible(self, axis_ctx: AxisTestContext, motor_ctx: MotorTestContext): - return axis_ctx.yaml == motor_ctx.yaml['name'] # check if connected + def get_test_cases(self, testrig: TestRig): + """Returns all axes that are connected to a motor, along with the corresponding motor(s)""" + for odrive in testrig.get_components(ODriveComponent): + for axis in odrive.axes: + for motor in testrig.get_connected_components(axis, MotorComponent): + yield (axis, motor) - def run_test(self, axis_ctx: AxisTestContext, motor_ctx: MotorTestContext, logger: Logger): + def run_test(self, axis_ctx: ODriveAxisComponent, motor_ctx: MotorComponent, logger: Logger): # reset old calibration values axis_ctx.handle.motor.config.phase_resistance = 0.0 axis_ctx.handle.motor.config.phase_inductance = 0.0 axis_ctx.handle.motor.config.pre_calibrated = False + axis_ctx.handle.config.enable_watchdog = False axis_ctx.handle.clear_errors() @@ -47,10 +49,14 @@ class TestDisconnectedMotorCalibration(): Tests if the motor calibration fails as expected if the phases are floating. """ - def is_compatible(self, axis_ctx: AxisTestContext): - return axis_ctx.yaml == 'floating' + def get_test_cases(self, testrig: TestRig): + """Returns all axes that are disconnected""" + for odrive in testrig.get_components(ODriveComponent): + for axis in odrive.axes: + if axis.yaml == 'floating': + yield (axis,) - def run_test(self, axis_ctx: AxisTestContext, logger: Logger): + def run_test(self, axis_ctx: ODriveAxisComponent, logger: Logger): axis = axis_ctx.handle # reset old calibration values @@ -73,14 +79,21 @@ class TestEncoderDirFind(): Runs the encoder index search. """ - def is_compatible(self, axis_ctx: AxisTestContext, motor_ctx: MotorTestContext, enc_ctx: EncoderTestContext): - return (axis_ctx.yaml == motor_ctx.yaml['name']) and (axis_ctx.num == enc_ctx.num) # check if connected + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + for num in range(2): + encoders = testrig.get_connected_components({ + 'a': (odrive.encoders[num].a, False), + 'b': (odrive.encoders[num].b, False) + }, EncoderComponent) + motors = testrig.get_connected_components(odrive.axes[num], MotorComponent) - def run_test(self, axis_ctx: AxisTestContext, motor_ctx: MotorTestContext, enc_ctx: EncoderTestContext, logger: Logger): + for motor, encoder in itertools.product(motors, encoders): + if encoder.impl in testrig.get_connected_components(motor): + yield (odrive.axes[num], motor, encoder) + + def run_test(self, axis_ctx: ODriveAxisComponent, motor_ctx: MotorComponent, enc_ctx: EncoderComponent, logger: Logger): axis = axis_ctx.handle - # TODO: read teensy config from YAML file - hexfile = 'encoder_pass_through.ino.hex' - program_teensy(os.path.join(os.path.dirname(__file__), hexfile), 26, logger) time.sleep(1.0) # wait for PLLs to stabilize # Set motor calibration values @@ -110,14 +123,21 @@ class TestEncoderOffsetCalibration(): Runs the encoder index search. """ - def is_compatible(self, axis_ctx: AxisTestContext, motor_ctx: MotorTestContext, enc_ctx: EncoderTestContext): - return (axis_ctx.yaml == motor_ctx.yaml['name']) and (axis_ctx.num == enc_ctx.num) # check if connected + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + for num in range(2): + encoders = testrig.get_connected_components({ + 'a': (odrive.encoders[num].a, False), + 'b': (odrive.encoders[num].b, False) + }, EncoderComponent) + motors = testrig.get_connected_components(odrive.axes[num], MotorComponent) - def run_test(self, axis_ctx: AxisTestContext, motor_ctx: MotorTestContext, enc_ctx: EncoderTestContext, logger: Logger): + for motor, encoder in itertools.product(motors, encoders): + if encoder.impl in testrig.get_connected_components(motor): + yield (odrive.axes[num], motor, encoder) + + def run_test(self, axis_ctx: ODriveAxisComponent, motor_ctx: MotorComponent, enc_ctx: EncoderComponent, logger: Logger): axis = axis_ctx.handle - # TODO: read teensy config from YAML file - hexfile = 'encoder_pass_through.ino.hex' - program_teensy(os.path.join(os.path.dirname(__file__), hexfile), 26, logger) time.sleep(1.0) # wait for PLLs to stabilize # Set motor calibration values @@ -127,9 +147,9 @@ class TestEncoderOffsetCalibration(): # Set calibration settings axis_ctx.handle.motor.config.direction = 0 - enc_ctx.handle.config.use_index = False - enc_ctx.handle.config.calib_scan_omega = 12.566 # 2 electrical revolutions per second - enc_ctx.handle.config.calib_scan_distance = 50.265 # 8 revolutions + axis_ctx.handle.encoder.config.use_index = False + axis_ctx.handle.encoder.config.calib_scan_omega = 12.566 # 2 electrical revolutions per second + axis_ctx.handle.encoder.config.calib_scan_distance = 50.265 # 8 revolutions axis_ctx.handle.clear_errors() @@ -141,7 +161,7 @@ class TestEncoderOffsetCalibration(): test_assert_eq(axis_ctx.handle.current_state, AXIS_STATE_IDLE) test_assert_no_error(axis_ctx) - test_assert_eq(enc_ctx.handle.is_ready, True) + test_assert_eq(axis_ctx.handle.encoder.is_ready, True) test_assert_eq(axis_ctx.handle.motor.config.direction in [-1, 1], True) @@ -152,14 +172,27 @@ class TestEncoderIndexSearch(): host's GPIO. """ - def is_compatible(self, axis_ctx: AxisTestContext, motor_ctx: MotorTestContext, enc_ctx: EncoderTestContext): - return (axis_ctx.yaml == motor_ctx.yaml['name']) and (axis_ctx.num == enc_ctx.num) # check if connected + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + for num in range(2): + encoders = testrig.get_connected_components({ + 'a': (odrive.encoders[num].a, False), + 'b': (odrive.encoders[num].b, False) + }, EncoderComponent) + motors = testrig.get_connected_components(odrive.axes[num], MotorComponent) + z_gpio = list(testrig.get_connected_components((odrive.encoders[num].z, False), LinuxGpioComponent)) - def run_test(self, axis_ctx: AxisTestContext, motor_ctx: MotorTestContext, enc_ctx: EncoderTestContext, logger: Logger): + for motor, encoder in itertools.product(motors, encoders): + if encoder.impl in testrig.get_connected_components(motor): + yield (odrive.axes[num], motor, encoder, z_gpio) + + def run_test(self, axis_ctx: ODriveAxisComponent, motor_ctx: MotorComponent, enc_ctx: EncoderComponent, z_gpio: LinuxGpioComponent, logger: Logger): axis = axis_ctx.handle - # TODO: read teensy config from YAML file - hexfile = 'encoder_pass_through.ino.hex' - program_teensy(os.path.join(os.path.dirname(__file__), hexfile), 26, logger) + cpr = int(enc_ctx.yaml['cpr']) + + z_gpio.config(output=True) + z_gpio.write(False) + time.sleep(1.0) # wait for PLLs to stabilize # Set motor calibration values @@ -177,24 +210,20 @@ class TestEncoderIndexSearch(): time.sleep(3) - test_assert_eq(enc_ctx.handle.index_found, False) - with open("/sys/class/gpio/gpio{}/direction".format(20), "w") as fp: - fp.write("out") - with open("/sys/class/gpio/gpio{}/value".format(20), "w") as gpio: - gpio.write("0") + test_assert_eq(axis_ctx.handle.encoder.index_found, False) time.sleep(0.1) - with open("/sys/class/gpio/gpio{}/value".format(20), "w") as gpio: - gpio.write("1") - test_assert_eq(enc_ctx.handle.index_found, True) + z_gpio.write(True) + test_assert_eq(axis_ctx.handle.encoder.index_found, True) + z_gpio.write(False) test_assert_eq(axis_ctx.handle.current_state, AXIS_STATE_IDLE) test_assert_no_error(axis_ctx) - test_assert_eq(enc_ctx.handle.shadow_count, 0.0, range=20) - test_assert_eq(enc_ctx.handle.count_in_cpr, 0.0, range=20) - test_assert_eq(enc_ctx.handle.pos_estimate, 0.0, range=20) - test_assert_eq(enc_ctx.handle.pos_cpr, 0.0, range=20) - test_assert_eq(enc_ctx.handle.pos_abs, 0.0, range=20) + test_assert_eq(axis_ctx.handle.encoder.shadow_count, 0.0, range=20) + test_assert_eq(modpm(axis_ctx.handle.encoder.count_in_cpr, cpr), 0.0, range=20) + test_assert_eq(axis_ctx.handle.encoder.pos_estimate, 0.0, range=20) + test_assert_eq(axis_ctx.handle.encoder.pos_cpr, 0.0, range=20) + test_assert_eq(axis_ctx.handle.encoder.pos_abs, 0.0, range=20) if __name__ == '__main__': diff --git a/tools/odrive/tests/can_test.py b/tools/odrive/tests/can_test.py index 344d94fe..7db9c5a6 100644 --- a/tools/odrive/tests/can_test.py +++ b/tools/odrive/tests/can_test.py @@ -7,8 +7,8 @@ import asyncio import time from fibre.utils import Logger -from odrive.enums import errors -from test_runner import CANTestContext, ODriveTestContext, test_assert_eq +from odrive.enums import * +from test_runner import * # Each argument is described as tuple (name, format, scale). # Struct format codes: https://docs.python.org/2/library/struct.html @@ -81,10 +81,12 @@ async def request(bus, node_id, cmd_name, timeout = 1.0): class TestSimpleCAN(): - def is_compatible(self, canbus: CANTestContext, odrive: ODriveTestContext): - return canbus.yaml['bus'] == odrive.yaml['can'] # check if connected + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + can_interfaces = testrig.get_connected_components(odrive.can, CanInterfaceComponent) + yield (odrive, list(can_interfaces)) - def run_test(self, canbus: CANTestContext, odrive: ODriveTestContext, logger: Logger): + def run_test(self, odrive: ODriveComponent, canbus: CanInterfaceComponent, logger: Logger): node_id = 0 axis = odrive.handle.axis0 axis.config.can_node_id = node_id @@ -139,11 +141,13 @@ class TestSimpleCAN(): test_assert_eq(axis.controller.input_vel, 2.0, range=0.01) test_assert_eq(axis.controller.input_current, 3.0, range=0.001) + axis.controller.config.control_mode = CTRL_MODE_VELOCITY_CONTROL my_cmd('set_input_vel', input_vel=-10.0, cur_ff=30.1234) fence() test_assert_eq(axis.controller.input_vel, -10.0, range=0.01) test_assert_eq(axis.controller.input_current, 30.1234, range=0.01) + axis.controller.config.control_mode = CTRL_MODE_CURRENT_CONTROL my_cmd('set_input_current', input_current=3.1415) fence() test_assert_eq(axis.controller.input_current, 3.1415, range=0.01) diff --git a/tools/odrive/tests/enc0_sim_-4096cps.ino.hex b/tools/odrive/tests/enc0_sim_-4096cps.ino.hex deleted file mode 100644 index 78b4d734..00000000 --- a/tools/odrive/tests/enc0_sim_-4096cps.ino.hex +++ /dev/null @@ -1,795 +0,0 @@ -:0200000460009A -:100000004643464200000156000000000101020084 -:1000100000000000000000000000000000000000E0 -:1000200000000000000000000000000000000000D0 -:1000300000000000000000000000000000000000C0 -:1000400000000000010403000000000000000000A8 -:100050000000200000000000000000000000000080 -:100060000000000000000000000000000000000090 -:100070000000000000000000000000000000000080 -:10008000EB04180A063204260000000000000000FD -:10009000050404240000000000000000000000002F -:1000A0000000000000000000000000000000000050 -:1000B0000604000000000000000000000000000036 -:1000C0000000000000000000000000000000000030 -:1000D00020041808000000000000000000000000DC -:1000E0000000000000000000000000000000000010 -:1000F0000000000000000000000000000000000000 -:10010000D8041808000000000000000000000000F3 -:100110000204180804200000000000000000000095 -:1001200000000000000000000000000000000000CF -:10013000600400000000000000000000000000005B -:1001400000000000000000000000000000000000AF -:10015000000000000000000000000000000000009F -:10016000000000000000000000000000000000008F -:10017000000000000000000000000000000000007F -:10018000000000000000000000000000000000006F -:10019000000000000000000000000000000000005F -:1001A000000000000000000000000000000000004F -:1001B000000000000000000000000000000000003F -:1001C000000100000010000001000000000000001D -:1001D000000001000000000000000000000000001E -:1001E000000000000000000000000000000000000F -:1001F00000000000000000000000000000000000FF -:10020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE -:10021000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE -:10022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE -:10023000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE -:10024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE -:10025000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE -:10026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E -:10027000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E -:10028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E -:10029000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E -:1002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E -:1002B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E -:1002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E -:1002D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E -:1002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E -:1002F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E -:10030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD -:10031000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED -:10032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD -:10033000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD -:10034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD -:10035000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD -:10036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D -:10037000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D -:10038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D -:10039000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D -:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D -:1003B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D -:1003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D -:1003D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D -:1003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D -:1003F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D -:10040000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC -:10041000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC -:10042000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC -:10043000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC -:10044000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC -:10045000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC -:10046000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C -:10047000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C -:10048000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C -:10049000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C -:1004A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C -:1004B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C -:1004C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C -:1004D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C -:1004E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C -:1004F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C -:10050000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB -:10051000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB -:10052000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB -:10053000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB -:10054000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB -:10055000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB -:10056000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B -:10057000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B -:10058000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B -:10059000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B -:1005A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B -:1005B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B -:1005C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B -:1005D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B -:1005E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B -:1005F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B -:10060000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA -:10061000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA -:10062000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA -:10063000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA -:10064000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA -:10065000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA -:10066000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A -:10067000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A -:10068000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A -:10069000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A -:1006A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A -:1006B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A -:1006C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A -:1006D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A -:1006E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A -:1006F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A -:10070000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 -:10071000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 -:10072000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 -:10073000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 -:10074000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 -:10075000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 -:10076000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 -:10077000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 -:10078000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 -:10079000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 -:1007A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 -:1007B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 -:1007C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 -:1007D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 -:1007E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 -:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 -:10080000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 -:10081000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 -:10082000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 -:10083000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 -:10084000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 -:10085000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 -:10086000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 -:10087000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 -:10088000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 -:10089000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 -:1008A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 -:1008B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 -:1008C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 -:1008D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 -:1008E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 -:1008F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 -:10090000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 -:10091000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 -:10092000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 -:10093000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 -:10094000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 -:10095000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 -:10096000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 -:10097000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 -:10098000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 -:10099000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 -:1009A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 -:1009B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 -:1009C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 -:1009D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 -:1009E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 -:1009F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 -:100A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 -:100A1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 -:100A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 -:100A3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 -:100A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 -:100A5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 -:100A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 -:100A7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 -:100A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 -:100A9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 -:100AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 -:100AB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 -:100AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 -:100AD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 -:100AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 -:100AF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 -:100B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 -:100B1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 -:100B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 -:100B3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 -:100B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 -:100B5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 -:100B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 -:100B7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 -:100B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 -:100B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 -:100BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 -:100BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 -:100BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 -:100BD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 -:100BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 -:100BF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 -:100C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 -:100C1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 -:100C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 -:100C3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 -:100C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 -:100C5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 -:100C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 -:100C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 -:100C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 -:100C9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 -:100CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 -:100CB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 -:100CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 -:100CD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 -:100CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 -:100CF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 -:100D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 -:100D1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 -:100D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 -:100D3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 -:100D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 -:100D5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 -:100D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 -:100D7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 -:100D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 -:100D9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 -:100DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 -:100DB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 -:100DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 -:100DD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 -:100DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 -:100DF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 -:100E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 -:100E1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 -:100E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 -:100E3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 -:100E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 -:100E5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 -:100E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 -:100E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 -:100E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 -:100E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 -:100EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 -:100EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 -:100EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 -:100ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 -:100EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 -:100EF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 -:100F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 -:100F1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 -:100F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 -:100F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 -:100F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 -:100F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 -:100F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 -:100F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 -:100F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 -:100F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 -:100FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 -:100FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 -:100FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 -:100FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 -:100FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 -:100FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 -:10100000D10020402C100060000000000000000013 -:1010100020100060001000600000000000000000D0 -:10102000000000607031000000000000000001209E -:1010300035100060764B0720764C4FF42A01764A33 -:101040005C64186499639546744A75498A420FD066 -:10105000744B9A420CD2D4430846234423F0030332 -:1010600004330B4450F8041B984242F8041BF9D196 -:101070006D4A6E498A420FD06D4B9A420CD2D443CE -:101080000846234423F0030304330B4450F8041BA5 -:10109000984242F8041BF9D1664A674B9A420BD238 -:1010A000D04311460024034423F0030304331344C4 -:1010B00041F8044B8B42FBD1604A4FF47001604B06 -:1010C000116003F530715F4A43F8042F9942FBD158 -:1010D0005D4B80215D4A03F8011B9342FBD15C4CC0 -:1010E0004FF080375B4E4FF0FF32DFF8A8A10025AC -:1010F000DFF8A491DFF8A481574B4549C3F800A05D -:10110000C4F80471C4F80091C4F8F470C4F8F08015 -:10111000F36923F07F0343F04003F361736A23F024 -:101120007F0343F0400373628A66CA660A674A67B0 -:1011300000F0B6F8494A6320494B4A49106003223F -:101140001D60CAF8381043F8082C4749474A4848F8 -:10115000C3F8082D0B68474A43F08073CAF83C0077 -:1011600045480B601368454943F001031360036869 -:101170000B6000F0E5F8C4F804714148C4F8009130 -:10118000C4F8F470C4F8F08000F03AFA00BF00BF71 -:1011900000BF00BFF16E3B4A41F440513A4BF1664B -:1011A0001560C2F80851C2F81851C2F82851C2F8A7 -:1011B00038519A6BD20708D442F615623349596503 -:1011C0001A659A6B42F001029A632F4A304C936879 -:1011D00043F00113936000F01BFA2368132BFCD932 -:1011E00000F05CF900F0D0F900F016FA00F0DAF83F -:1011F00000F0FEF92368B3F5967FFBD300F0FCF90D -:1012000000F00EFA00F018FA00F012FAFAE700BF48 -:1012100000C00A40ABAAAAAA008007200000000074 -:10122000501600605017000000000020A42D006040 -:10123000D0030020D0030020C032002088ED00E061 -:10124000FC0F00201D05000000E400E0A0E400E029 -:1012500000800D4000C00F4008ED00E014E000E009 -:1012600018E000E095100000FCED00E000002020F8 -:1012700099110000001000E0041000E0A40D00200F -:101280000046C3230040084000400D400000C05607 -:10129000A80D0020001000201B1018200C0D1113A9 -:1012A000F0B5194A0021194B4FF0100E18480124CF -:1012B000184E194D0160194FC2F800E01E6015600C -:1012C000174E184D1F601660174F1D60174E184DB2 -:1012D00017601E60174F1560174E184D1F6016607F -:1012E0001D600460BFF34F8FBFF36F8FC3F8B01161 -:1012F000BFF34F8FBFF36F8F52F8883C43F44033F6 -:1013000042F8883CF0BD00BF9CED00E0A0ED00E09D -:1013100094ED00E0250008031100200021000207E1 -:1013200012000020250008131300202027000B13B3 -:101330001400004033001013150000602F000B074D -:10134000F0B4174A40274FF480314FF480564FF4E1 -:1013500000554FF4404443F24200136913F0020F6A -:1013600006D0946151619061136913F0020FF8D1B6 -:1013700013F4005F01D15561EFE713F4805F01D1F1 -:101380005661EAE7002BE8DA13F4803F01D091615F -:10139000E3E75B0601D45761DFE7F0BC704700BFAD -:1013A00000800D40364A03203649F3EE096A13687F -:1013B00023F00103F0B51360C2F89000D1F8E030DB -:1013C000DFF8D4E0DCB2C3F30B202F4FC0EB135394 -:1013D00007EE904AA4F15501CEF80040B8EEE77A46 -:1013E00003EB830407EE900A03FB01F13B6003EB80 -:1013F0008313B8EEE75A07EE901A091B77EE666A78 -:10140000B8EE677A214D07EE901A0B44C5ED006ADD -:10141000F8EE677A1E4EC7EE265A1E4930601068F5 -:1014200087EEA66A07EE903AF8EE677A87EEA67A1C -:1014300075EE855A76EE056AFCEEE55AFCEEE66A34 -:1014400015EE903A40EA035316EE900A77EE057ACD -:10145000136001EA0041D2F81031FCEEE77A0B4349 -:10146000C2F8103117EE903AD2F81011C3F30B0303 -:101470000B43C2F81031136843F002031360F0BD50 -:1014800080810D4000441F40F8030020F403002039 -:10149000FC0300200000FF0FF0030020304B40F65B -:1014A000617270B5C3F8202140F2044500F0ACF839 -:1014B0002C492D48D1F880202C4C42F003022C4BB3 -:1014C000C1F88020C0F86051226813401BB9D0F8E1 -:1014D000A8319A071AD0244B4FF00041234A516398 -:1014E0001A46D3F8401141F00201C3F84011D2F876 -:1014F00040319B07FBD44FF400301E491B4B4FF08B -:101500000042086019209A6300F09AF81A4D0022F0 -:10151000164B4FF08041144C0A26996328461A60F6 -:101520001146C4F8A8614FF4207200F07DF84FF422 -:1015300081064FF4800040F24313104A10492E6098 -:101540002864C4F85851C2F80412C4F848310D4A4E -:101550004FF4003101231160C4F8403170BD00BF69 -:1015600000800D4000C00F4000002E4000900D4054 -:10157000001C1E008CE200E0003000200010002063 -:10158000F90600000CE100E0114B1249D86E0A4642 -:1015900040F4403030B4D86640F2B765D86EA0242D -:1015A00040F44070D8664D648C64936C1B06FCD488 -:1015B000094B40F2B760A021064A58649964936CC5 -:1015C00013F08003FBD1054A137030BC704700BF95 -:1015D00000C00F4000400C4000800C40A10D0020D6 -:1015E000F8B500BFF8BC08BC9E467047FFFFFFFF80 -:1015F0005FF800F0390500005FF800F055160000B4 -:101600005FF800F0D90100005FF800F0F90D00006C -:101610005FF800F0350500005FF800F06913000086 -:101620005FF800F0010100005FF800F0A51600006F -:101630005FF800F0B91100005FF800F0050100004C -:101640005FF800F05912000045000000FFFFFFFFA7 -:10165000000000000000000000000000000000008A -:10166000000000000000000000000000000000007A -:1016700010B5054C237833B9044B13B10448AFF3CC -:1016800000800123237010BDD00300200000000063 -:1016900054170000084B10B51BB108490848AFF3B8 -:1016A00000800848036803B910BD074B002BFBD02E -:1016B000BDE81040184700BF00000000D403002020 -:1016C00054170000D00300200000000008B5174B9D -:1016D0000121187800F00AFA154B0121187800F062 -:1016E00005FA144B0121187800F000FA124B012181 -:1016F000187800F0FBF9114B0121187800F0F6F989 -:101700000F4B0121187800F0F1F90E4B00211878E9 -:1017100000F0ECF90C4B0021187800F0E7F90B4BC6 -:1017200000211878BDE8084000F0E0B9F40200207C -:10173000FC0200200003002010030020080300200A -:10174000F8020020EC030020EC020020F002002050 -:10175000FFF7BCBF2C4A2D4B2DE9F04714682C4AEB -:10176000DFF8B8A012685746DFF8B490294EDFF8CA -:10177000B480294D93FBF4F393FBF2F4012199F823 -:10178000000000F0ADF9DAF800103268A5FB023273 -:10179000920C04FB02F2DAF800305B1A9A42FAD893 -:1017A000012198F8000000F09BF939683268A5FB28 -:1017B0000232920C04FB02F2DAF800305B1A9A4211 -:1017C000FAD8002199F8000000F08AF939683268E7 -:1017D000A5FB0232920C04FB02F2DAF800305B1A2D -:1017E0009A42FAD8002198F8000000F079F9396897 -:1017F0003268A5FB0232920C04FB02F2DAF80030E8 -:101800005B1A9A42FAD8B9E70C03002000879303C9 -:10181000040300201803002083DE1B43041000E0B3 -:10182000FC020020000300208C4A8D4B90422DE9E1 -:10183000F0438C4D5C699969EF681DD98A4B9842D9 -:1018400040F20181894B40F22766DFF860E20344F1 -:10185000874D1A0AAEFB0232D30903EB830303EB75 -:10186000830202F2E243B34228BF3346A3F5487332 -:10187000A5FB0336F60804E07E4EB04294BF062670 -:101880000E26774A07F01F0ED2F88030B64543F097 -:10189000C003C2F880300AD2724B27F01F071A46E5 -:1018A0003743DF601368002BFCDA07F01F0E14F0DB -:1018B00000732ED1704D714AD5F810C015460CEA50 -:1018C0000202AA420ABF4FF0C0534FF480520022D6 -:1018D00084EA030515F0605F06D024F0605403F03D -:1018E00060535F4D1C436C6181EA020313F4405F57 -:1018F00008D05B4B21F4405111431A469961936C17 -:101900001D07FCD444F00074554A5461936C990649 -:10191000FCD401215A4D0A4601FB02F300FB03F3FC -:10192000AB4209D8072A00F28480013201FB02F39E -:1019300000FB03F3AB42F5D95248534D1844A5FBC5 -:101940000030030D6C2B79D8352B7ED8DFF8608101 -:1019500036234E48DFF820C14D4DDCF80090B0FB37 -:10196000F2F009EA05054545B0FBF1F00BD043F470 -:1019700000534FF480586546CCF80080CCF8003016 -:101980002B68002BFCDADFF8D8C0013ADCF8103005 -:1019900003F00703934207D002F007026546CCF834 -:1019A0001020AB6CDB03FCD40139890284EA01030B -:1019B00013F4E05F0AD02A4B24F4E05401F4E05120 -:1019C0001A460C435C61936C9907FCD4314B324945 -:1019D0000344DB09A1FB0331090B042928BF0421BF -:1019E0004B1E1B0284EA030212F4407F06D024F44B -:1019F000407403F440731A4A1C435461184B24F09A -:101A000000741A465C61936C9B06FCD4B0FBF1F148 -:101A1000224A7645224B1060196008D2114B27F0FC -:101A20001F071A463743DF601368002BFCDABDE856 -:101A3000F083042980D8013101226DE7DFF874803A -:101A40006C23184886E712261BE71748DFF86880E2 -:101A500000FB03F043EA08087CE700BF00A4781FFE -:101A600000C00F40000008400046C32300BA3CDC21 -:101A70001F85EB5100366E0100800D404030008024 -:101A8000FFB19F26808D5B00819F5E1600B29F266E -:101A90007F3001807FD1F0089F10E50018030020FF -:101AA0001403002000643F4D001BB70023B24C001C -:101AB000362000806C200080002000800001074B51 -:101AC0001A181B58D2685868104202D011B9C3F8CE -:101AD00088207047C3F88420704700BF00000020B2 -:101AE000272801D8FFF7EABF704700BF27281CD876 -:101AF00000011A4A012902EB0003105810B415D056 -:101B0000042913D0DC68426822EA040242609A6821 -:101B1000E9B102291ED003295B685DF8044B0CBFB4 -:101B20000F491049116015221A607047DA680129BF -:101B3000446842EA040242609A6808D040F63801DC -:101B400011605B6815225DF8044B1A6070473821FC -:101B50001160F6E704491160F3E700BF00000020C0 -:101B6000383001003800010038F0010004207146CF -:101B7000084203D0EFF3098000F008B8EFF30880C3 -:101B800000F004B8704700BF704700BF1B4B052131 -:101B90001B4A382030B5C2F848110821C2F8380372 -:101BA00083B05A68174C0A4317485A60C3F8841028 -:101BB000C3F888102368834202D91448FFF734FE23 -:101BC0000E4D08240020124A1249C5F884400190A5 -:101BD000019B934205D8019B01330193019B9342E2 -:101BE000F9D9C5F888400190019B8B42EDD8019B43 -:101BF00001330193019B8B42F9D9E6E700C01B40FA -:101C000000801F4018030020FF45C32300A3E111FB -:101C10003F420F003F548900836B30B41BB15368BF -:101C200043F40043536072B6446B9CB1104B226086 -:101C3000D3F8B0410C4217D1D3F8404144F480446A -:101C4000C3F84041D3F8B851D3F840416404F3D508 -:101C5000294209D10023064C8260C360D4F8B03118 -:101C60001943C4F8B0110263426362B630BC7047D6 -:101C700000002E4038B50546036B06E0AA6B1C68D1 -:101C800090476A6B2346944208D0184633B1012B23 -:101C900004D05A681206F1D52B6338BD00232B639C -:101CA0006B6338BDF0B5F1B9224C23490020234BBA -:101CB00001228025A1600A601A464D60E060D3F8D9 -:101CC000BC41886044F001141D4DC3F8BC41D3F8F9 -:101CD000B01141F00101C3F8B0112860D2F8B03161 -:101CE000002BFBD1F0BD0904164B144D0126114CFD -:101CF00041F0800100221E60596000F5805CE264C2 -:101D000000F5005EA36400F54057D5F8B01100F56A -:101D100080462A46986041F48031C3F80CC0C3F86D -:101D200010E05F619E61C5F8B011D2F8B031002BB0 -:101D3000FBD1BAE7003000202020002000002E4018 -:101D40000C040020002000202DE9F04FBB4C83B094 -:101D5000D4F8448118F0010FC4F844815ED0D4F85F -:101D6000AC31002B55D04FF00119DFF8F0B2264608 -:101D7000B34FCA46B96AFA6AC4F8AC31D4F84031F4 -:101D800043F40053C4F84031D4F840319D04F5D5F4 -:101D9000D6F8403123F40053C6F84031C6F8B4A158 -:101DA000D4F8B43113F00113FAD188B240F281654E -:101DB000CBF80030A84200F29680B0F5D06F80F0EA -:101DC000D881B0F5817F00F0578100F2D58080285E -:101DD00000F02681822840F0C78092B202F07F0195 -:101DE000072900F2C18089009648974D0844016890 -:101DF00010062B706B7040F1E581C90301D50123FA -:101E00002B7002219048FFF74DFFD4F8AC31002B26 -:101E1000B0D18A4AD2F8BC31002B44D118F0400F1F -:101E200018D0864BD3F8AC111A46C3F8AC11D3F8CE -:101E3000BC11C3F8BC11D2F8B041804B002CFAD1D0 -:101E40004FF0FF32C3F8B421D3F8843100F074FBB3 -:101E50007E4B1C6018F0807F03D07D4B1B6803B164 -:101E6000984718F0007F03D07A4B1B6803B198475E -:101E700018F0040F02D0714BD3F884316F4BD3F8B4 -:101E8000482112060CD518F0800F09D072490A7843 -:101E9000002A00F08E81531EDBB20B7003B9FBBE2B -:101EA00003B0BDE8F08F6D49C2F8BC310868034249 -:101EB00040F0CC81654A14681C40AFD0630700F144 -:101EC000E281670300F1EF81260700F1E881250335 -:101ED00000F1E181E00600F1DA81E1029ED560487F -:101EE000FFF7C8FE9AE742F22105A84238D06FD822 -:101EF000B0F5086F00F02F81B0F5106F34D1C1F349 -:101F00000741584A584811705849594A0193C6F830 -:101F1000C801C6F8CC11C6F8D02100F00FFB554A15 -:101F2000019B80210120FB6410605160D6F8BC1138 -:101F3000936041F00111BA64C6F8BC11D6F8B02123 -:101F400042F48032C6F8B021444A1360D4F8B0316C -:101F5000002BFBD1D4F8AC31002B7FF40BAF58E74A -:101F6000100C072800F03281C4F8C091D4F8AC31CD -:101F7000002B7FF4FFAE4CE740F20235A84200F0A0 -:101F8000B780B0F5A06FEFD13A4A80200125FB64FD -:101F900050601560D6F8BC01936040F00113BA643C -:101FA000C6F8BC31D6F8B03143F48033C6F8B0314E -:101FB000D4F8B031002BFBD10B0C5B0643F08073DF -:101FC000C6F85431D4F8AC31002B7FF4D3AE20E7FF -:101FD00042F22123984200F0828042F2213398425B -:101FE000C2D1244B01218022196000215A60D4F80B -:101FF000BC21BB6442F001129960F964C4F8BC21B1 -:10200000D4F8B03143F48033C4F8B031D4F8B031EF -:10201000002BFBD1D4F8AC31002B7FF4ABAEF8E64B -:10202000094A0221104613705370FFF73BFED4F8A3 -:10203000AC31002B7FF49EAEEBE600BF00002E40DB -:1020400000300020C0012E402004002004040020A5 -:102050000004002008040020100400200C040020CC -:1020600040320020300400200200CC00C8000200F2 -:102070000200C8002020002092B202F07F03072B4C -:102080003FF672AF12F0800F4FEA8303884A4FF099 -:1020900001011A44136814BF23F4803323F00103B1 -:1020A00013608022834B196000215A60D4F8BC2150 -:1020B000BB6442F001129960F964C4F8BC21D4F801 -:1020C000B03143F48033C4F8B031D4F8B031002BD0 -:1020D000FBD1D4F8AC31002B7FF44CAE99E6764BB3 -:1020E000C1F30741754A1868754B1060197078E79D -:1020F00092B202F07F03072B3FF636AF12F0800F4B -:102100004FEA83036A4A4FF001011A44136814BF6F -:1021100043F4803343F0010313608022654B196060 -:1021200000215A60D4F8BC21BB6442F001129960CE -:10213000F964C4F8BC21D4F8B03143F48033C4F856 -:10214000B031D4F8B031002BFBD1D4F8AC31002B36 -:102150007FF410AE5DE65B4A01215B4B12781846B6 -:102160001A70FFF79FFDD4F8AC31002B7FF402AE5C -:102170004FE6564B586800283FF4F6AE090C1FFA9C -:1021800082FE04E00C33586800283FF4EDAE1D8851 -:102190008D42F7D15D887545F4D1090A120C0329E7 -:1021A0000CBF01781989914228BF1146FFF77AFDCB -:1021B0002BE6D3F8482122F08002C3F8482103B06F -:1021C000BDE8F08FCA077FF51CAE18E6404D012030 -:1021D000FB6029603F4B4049186059603F49D6F881 -:1021E000B0016A6001F5005E40F00102A1F5005007 -:1021F00001F58055BB609860A1F58050D860C6F8A5 -:10220000B02119615D61C3F818E0D4F8B031002B3A -:10221000FBD1284A012048F28001FB6410604FF492 -:1022200080305160D6F8BC11936041F00113BA645C -:10223000C6F8BC31D6F8B0310343C6F8B031CBF89C -:102240000000D4F8B031002BFBD1DEE5204C42F287 -:102250002100002524880D6084427FF42BAE2049A4 -:10226000204C03C90D0C86282060A180A5717FF445 -:1022700021AED2F8481150241B4841F08001C2F829 -:102280004811047016E61948FFF7F4FC19E61848DF -:10229000FFF7F0FC21E61748FFF7ECFC1AE61648BA -:1022A000FFF7E8FC13E61548FFF7E4FC0CE600BF77 -:1022B000C0012E4020200020A80D002088320020E0 -:1022C000800D002030040020200400208002002027 -:1022D000180400200020002080000700282400208F -:1022E000280400208032002010040020003100204B -:1022F00000320020C0310020803100204031002019 -:10230000002AA0F102022DE9F04714BF00274FF088 -:102310000057022A01D9BDE8F0874FEAC01ADFF85A -:1023200040900D4604460AEB0906002140229846DB -:10233000304600F0DFFC012047EA05414AF8091069 -:10234000C6F83880B060B8F1000FE4D0034BA0406D -:102350001C6820431860BDE8F08700BF040400201B -:1023600000300020002AA0F102022DE9F04714BF3E -:1023700000274FF00057022A01D9BDE8F08740221C -:10238000C501DFF8449088461544002104461E46E6 -:1023900005EB090A504600F0ADFC012247EA08416E -:1023A00045F80910CAF83860CAF80820002EE4D0B1 -:1023B00004F11000034B8240186802431A60BDE824 -:1023C000F08700BF04040020003000201204816068 -:1023D000C36142F08002F0B44260012701F58056EB -:1023E00001F5005501F5405401F580420760C660D3 -:1023F000056144618261F0BC704700BF831E022BFF -:1024000000D9704730B4064B00F1100401250A468C -:1024100003EBC01005FA04F130BCFFF7FDBB00BFB1 -:1024200040300020831E022B00D9704710B4054BAA -:1024300001240A4604FA00F103EBC0105DF8044BD6 -:10244000FFF7EABB00300020124A134BD2F82002FB -:1024500020F07F40984210B584B002D800EB800095 -:1024600040000E4C01A90A2200F07EFA01A90023C7 -:10247000204611F8012B01333AB10A2B20F8022F24 -:10248000F7D11623237004B010BD5B00DBB22370BC -:1024900004B010BD00441F407F969800B403002094 -:1024A0004368C269C3F30E43054930B4C3F1400326 -:1024B000044C002521F8123024F8125030BC70472B -:1024C000000C0020F80B0020F8B5154B1B783BB929 -:1024D00003F0FF04134B1B7813B1134D2A8802B984 -:1024E000F8BD124F2346124EC2F58072397811485A -:1024F00006EB411600EB01213046FFF767FF31463E -:102500000420FFF77BFF3B780133DBB2062B98BF3B -:102510003B704FF0000388BF3C702B80F8BD00BFBC -:10252000340B002030040020800C0020350B0020EC -:10253000A00C002034040020704700BF0021E022DE -:102540002048F8B50C46204E204D00F0D3FB204F1C -:102550002146204B6022347028461F4E1C8000F01C -:10256000C9FB23462246102102203C60BC80346017 -:10257000B480FFF7F7FE2246184B40210320FFF7F7 -:10258000BFFE2346224640210420FFF7EBFE2346F0 -:10259000402228461249FFF719FF29460320FFF77A -:1025A00041FF104B4A22104910480860C3F884408C -:1025B000C3F88020D3F8482142F08072C3F8482144 -:1025C000F8BD00BFA00C0020350B0020200C00201F -:1025D000000C0020800C0020F80B0020510E0000A1 -:1025E000380B002000002E4000040020790E00006F -:1025F000024A034B10881B88C01A7047000C002049 -:10260000F80B002010B4EFF3108272B6437F33B999 -:10261000017F012908D0032910D00123437702B993 -:1026200062B65DF8044B7047114C2168A1B11149A5 -:1026300043610B68086083615861EEE70E4C2168C6 -:1026400081B10E4943610B680860836158610C4B8E -:102650004FF080511960E0E7064B416181612060D5 -:102660001860DAE7054B4161816120601860EEE790 -:10267000940D0020900D0020840D0020880D002076 -:1026800004ED00E010B4047F4160022CC26003D06E -:102690005DF8044BFFF7B6BF83685DF8044B18473D -:1026A00070B5EFF3108172B60C4C23688BB10C4EF1 -:1026B00000255A6922607AB1956101B962B65D77E9 -:1026C00018469B689847EFF3108172B62368002B79 -:1026D000EFD101B962B670BD3260EEE7840D002023 -:1026E000880D0020FFF7DCBF184A30B41468002CB6 -:1026F00028D0036821688B420FD2CB1A0021846056 -:10270000C1602360E0601060022330BC0375704735 -:102710000360144611688B4208D3A2685B1A002A32 -:10272000F6D18260C4600360A060EDE7D568CB1A83 -:1027300082600222C560E060C16888602360027523 -:1027400030BC70478460C4601060DDE78C0D0020F1 -:10275000F8B5224E34682CB32368002B3AD11D46BD -:102760001F4F04E03468ECB12368002B32D1A3681A -:1027700003B1DD6020693360036825751B68BB42C7 -:1027800021D1037F4560022BC46020D0FFF73AFFC0 -:102790006368002BE6D023602046FFF7A5FF34686E -:1027A000002CE1D1EFF3108372B60E4A00211068BD -:1027B000116003B962B628B18468FFF795FF20461F -:1027C0000028F9D1F8BD224600219847E0E7836848 -:1027D0009847DDE7013B2360E4E700BF8C0D002054 -:1027E000351000009C0D0020044A054B1168054A75 -:1027F0001960136801331360FFF7AABF041000E0EB -:10280000A40D0020A80D002070B5214C237883B9B9 -:10281000204B01221B7822701BBB1F4B1B78002B07 -:1028200029D11E4B00211A68217012B1EFF30582E5 -:1028300002B170BDEFF3108072B61A68F2B1184C95 -:102840002178D9B90126556926701D60D5B1A961D5 -:1028500000B962B6002593681046557798472570F1 -:1028600070BDFFF7C5FE0028D7D000F015FA0A4B5F -:102870001B78002BD5D000F0FBF9D2E70028D8D187 -:1028800062B670BD074B1D600028E3D1E1E700BFD1 -:10289000A00D0020CA030020C80D0020940D0020C8 -:1028A000980D0020900D0020002852D02DE9F04F07 -:1028B000814683B0274C0120274D284E54E8003F25 -:1028C0002A68316844E80003002BF7D1244F4FF405 -:1028D0007A7E2448D7F800C0BB4607F1C647036894 -:1028E000C1EB0C0107F5DE1707F67F67A7FB03C3F3 -:1028F000BA4601279B0CB1FBF3F30EFB023854E8F8 -:10290000003F2A68316844E80073002BF7D1DBF8F8 -:1029100000C04FF47A7E03680EFB02F2C1EB0C019B -:10292000AAFB033EC8EB02034FEA9E42B1FBF2F161 -:10293000CA18B2F57A7F07D3B9F1010908F57A7898 -:10294000DDD103B0BDE8F08F0190FFF75DFF019886 -:10295000D5E770478C320020A80D0020A40D002080 -:10296000041000E018030020F0B44E1E0025374686 -:1029700000E00135B0FBF2F302FB130000F1370475 -:10298000092800F13000E4B298BFC4B2184607F835 -:10299000014F002BEDD14A1953704DB1013316F898 -:1029A000014F1778E81A3770834202F80149F5DBC6 -:1029B0000846F0BC704700BFA4484FF00F0CA44B72 -:1029C000826F42F47F02F0B582670025D0F8802044 -:1029D0004FF470469F4C4FF4604E29464FF4806789 -:1029E00014432A46C0F88040A3F88C6148F2B82608 -:1029F000A3F88EC1A3F89051B3F8880180B240F0DB -:102A0000F000A3F8880101EB4100914B0131002552 -:102A100040011C4604290344A3F804E0DF805A84E3 -:102A20001A865A805A81DE815A82DA825A83DA8380 -:102A3000E9D1B4F888014FF00F0C874B4FF4704682 -:102A400080B229464FF460472A4640EA0C004FF412 -:102A5000806EA4F88801B4F8880180B240F47060F8 -:102A6000A4F88801A3F88C6148F2B826A3F88EC1B7 -:102A7000A3F89051B3F8880180B240F0F000A3F8B9 -:102A8000880101EB4100744B0131002540011C46D7 -:102A9000042903449F80A3F806E05A841A865A80CA -:102AA0005A81DE815A82DA825A83DA83E9D1B4F814 -:102AB00088014FF00F0C694B4FF4704680B22946E5 -:102AC0004FF460472A4640EA0C004FF4806EA4F8A9 -:102AD0008801B4F8880180B240F47060A4F88801DD -:102AE000A3F88C6148F2B826A3F88EC1A3F89051E0 -:102AF000B3F8880180B240F0F000A3F8880101EB40 -:102B00004100564B0131002540011C460429034475 -:102B10009F80A3F806E05A841A865A805A81DE8183 -:102B20005A82DA825A83DA83E9D1B4F888014FF005 -:102B30000F0C4B4B4FF4704780B229464FF4604660 -:102B40002A4640EA0C004FF4806EA4F88801B4F8DD -:102B5000880180B240F47060A4F88801A3F88C71F9 -:102B600048F2B827A3F88EC1A3F89051B3F88801B2 -:102B700080B240F0F000A3F8880101EB4100384B2F -:102B8000013140011C46042903449E80A3F806E05D -:102B90005A841A865A805A81DF815A82DA825A838D -:102BA000DA83EAD1B4F888310F27002241F2010616 -:102BB0009BB245F6C05E114643F226053B43A4F89E -:102BC0008831B4F888319BB243F47063A4F888313B -:102BD0005001244B01320344042A99815981DF8139 -:102BE0009E82A3F806E0198019829D81F0D100220F -:102BF0000F2741F2010645F6C055114643F226045F -:102C00005001194B01320344042A99815981DF8113 -:102C10009E82DD80198019829C81F1D100220F27CC -:102C200041F2010645F6C055114643F22604500113 -:102C30000E4B01320344042A99815981DF819E821F -:102C4000DD80198019829C81F1D1F0BD00C00F4058 -:102C500000C03D40000003FC00003E4000403E40FC -:102C600000803E4000C01D4000001E4000401E404D -:102C700038B5074B1C784CB1064D55F8043F002B76 -:102C8000FBD09847631E13F0FF04F6D138BD00BF98 -:102C9000C80D0020A80D0020014B00221A707047BB -:102CA000CA03002070B50F4E0F4D761BB61018BF2B -:102CB000002405D0013455F8043B9847A642F9D1C9 -:102CC0000A4E0B4D761B00F063F8B61018BF0024B7 -:102CD00006D0013455F8043B9847A642F9D170BD9F -:102CE00070BD00BF48160060481600604C160060BA -:102CF0004816006070B4840746D0541E002A41D0A4 -:102D0000CDB2034602E0621EE4B3144603F8015B51 -:102D10009A07F8D1032C2ED9CDB245EA05250F2C00 -:102D200045EA054519D903F110022646103E0F2E3B -:102D300042F8105C42F80C5C42F8085C42F8045C13 -:102D400002F11002F2D8A4F1100222F00F0204F0F6 -:102D50000F041032032C13440DD91E462246043AA8 -:102D6000032A46F8045BFAD8221F22F00302043239 -:102D7000134404F003042CB1C9B21C4403F8011B32 -:102D8000A342FBD170BC704714460346C2E700BFA4 -:102D90005FF800F0E1150060000000000000000096 -:042DA000F8B500BFC3 -:102DA40000000042C8801F40B8821F400800000095 -:102DB40000000042C4801F40B4821F400400000091 -:102DC40000C0004224801F4014821F4010000000F5 -:102DD40000C0004228801F4018821F4020000000CD -:102DE40000C000422C801F401C821F404000000095 -:102DF40000C0004234801F4024821F4000010000B4 -:102E04000040004264811F4054831F4000040000BE -:102E14000040004280811F4070831F400000020078 -:102E2400004000427C811F406C831F400000010071 -:102E34000040004268811F4058831F400008000082 -:102E4400004000423C811F402C831F4001000000D1 -:102E54000040004244811F4034831F4004000000AE -:102E64000040004240811F4030831F4002000000A8 -:102E74000040004248811F4038831F400800000082 -:102E84000000004204811F40F4821F40000004003F -:102E94000000004208811F40F8821F400000080023 -:102EA4000000004218811F4008831F40000080007A -:102EB4000000004214811F4004831F4000004000B2 -:102EC4000000004200811F40F0821F400000020009 -:102ED40000000042FC801F40EC821F400000010003 -:102EE4000000004224811F4014831F40000000049E -:102EF4000000004228811F4018831F400000000882 -:102F0400000000421C811F400C831F400000000190 -:102F14000000004220811F4010831F400000000277 -:102F240000000042EC801F40DC821F4000100000C3 -:102F340000000042F0801F40E0821F40002000009B -:102F44000000004234811F4024831F4000000040E1 -:102F54000000004238811F4028831F400000008089 -:102F64000080004294801F4084821F4000000400BF -:102F740000C0004290801F4080821F4000000080FB -:102F840000800042A8801F4098821F4000008000FB -:102F940000800042A4801F4094821F400000400033 -:102FA400004000426C811F405C831F400010000001 -:102FB40000C0004230801F4020821F40800000007B -:102FC40000800042C8811F40B8831F400080000079 -:102FD40000800042C4811F40B4831F4000400000B1 -:102FE40000800042C0811F40B0831F4000200000C9 -:102FF40000800042BC811F40AC831F4000100000D1 -:1030040000800042D0811F40C0831F4000000200A6 -:1030140000800042CC811F40BC831F40000001009F -:1030240000010000840300201200000000060000DC -:103034001C0300200A0000000002000040030020DE -:10304400430000000007000040030020430000008C -:1030540000030000B0030020000000000103090485 -:103064002803002000000000020309049803002044 -:103074000000000003030904B40300200000000062 -:10308400000000000000000000000000010000003B -:1030940002000000170000001200000016000000EB -:1030A400150000001E0000001300000000200000B6 -:1030B400140000000029DE07007B9A170A060002AC -:1030C4000200004001000000180354006500650080 -:1030D4006E00730079006400750069006E006F0073 -:1030E40009024300020100C0320904000001020287 -:1030F4000100052400100105240101010424020635 -:1031040005240600010705820310001009040100CC -:10311400020A0000000705030240000007058402BC -:10312400400000001201000202000040C0168304A7 -:103134007902010203010000160355005300420006 -:103144002000530065007200690061006C000000FB -:10315400040309040C030000000000000000000048 -:10316400000000000000000000000100000000005A -:040000056000100087 -:00000001FF diff --git a/tools/odrive/tests/enc1_sim_-4096cps.ino.hex b/tools/odrive/tests/enc1_sim_-4096cps.ino.hex deleted file mode 100644 index 43eabc4b..00000000 --- a/tools/odrive/tests/enc1_sim_-4096cps.ino.hex +++ /dev/null @@ -1,795 +0,0 @@ -:0200000460009A -:100000004643464200000156000000000101020084 -:1000100000000000000000000000000000000000E0 -:1000200000000000000000000000000000000000D0 -:1000300000000000000000000000000000000000C0 -:1000400000000000010403000000000000000000A8 -:100050000000200000000000000000000000000080 -:100060000000000000000000000000000000000090 -:100070000000000000000000000000000000000080 -:10008000EB04180A063204260000000000000000FD -:10009000050404240000000000000000000000002F -:1000A0000000000000000000000000000000000050 -:1000B0000604000000000000000000000000000036 -:1000C0000000000000000000000000000000000030 -:1000D00020041808000000000000000000000000DC -:1000E0000000000000000000000000000000000010 -:1000F0000000000000000000000000000000000000 -:10010000D8041808000000000000000000000000F3 -:100110000204180804200000000000000000000095 -:1001200000000000000000000000000000000000CF -:10013000600400000000000000000000000000005B -:1001400000000000000000000000000000000000AF -:10015000000000000000000000000000000000009F -:10016000000000000000000000000000000000008F -:10017000000000000000000000000000000000007F -:10018000000000000000000000000000000000006F -:10019000000000000000000000000000000000005F -:1001A000000000000000000000000000000000004F -:1001B000000000000000000000000000000000003F -:1001C000000100000010000001000000000000001D -:1001D000000001000000000000000000000000001E -:1001E000000000000000000000000000000000000F -:1001F00000000000000000000000000000000000FF -:10020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE -:10021000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE -:10022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE -:10023000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE -:10024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE -:10025000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE -:10026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E -:10027000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E -:10028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E -:10029000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E -:1002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E -:1002B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E -:1002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E -:1002D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E -:1002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E -:1002F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E -:10030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD -:10031000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED -:10032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD -:10033000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD -:10034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD -:10035000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD -:10036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D -:10037000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D -:10038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D -:10039000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D -:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D -:1003B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D -:1003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D -:1003D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D -:1003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D -:1003F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D -:10040000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC -:10041000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC -:10042000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC -:10043000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC -:10044000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC -:10045000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC -:10046000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C -:10047000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C -:10048000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C -:10049000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C -:1004A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C -:1004B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C -:1004C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C -:1004D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C -:1004E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C -:1004F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C -:10050000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB -:10051000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB -:10052000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB -:10053000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB -:10054000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB -:10055000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB -:10056000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B -:10057000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B -:10058000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B -:10059000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B -:1005A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B -:1005B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B -:1005C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B -:1005D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B -:1005E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B -:1005F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B -:10060000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA -:10061000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA -:10062000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA -:10063000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA -:10064000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA -:10065000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA -:10066000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A -:10067000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A -:10068000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A -:10069000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A -:1006A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A -:1006B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A -:1006C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A -:1006D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A -:1006E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A -:1006F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A -:10070000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 -:10071000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 -:10072000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 -:10073000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 -:10074000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 -:10075000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 -:10076000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 -:10077000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 -:10078000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 -:10079000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 -:1007A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 -:1007B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 -:1007C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 -:1007D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 -:1007E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 -:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 -:10080000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 -:10081000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 -:10082000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 -:10083000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 -:10084000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 -:10085000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 -:10086000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 -:10087000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 -:10088000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 -:10089000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 -:1008A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 -:1008B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 -:1008C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 -:1008D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 -:1008E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 -:1008F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 -:10090000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 -:10091000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 -:10092000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 -:10093000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 -:10094000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 -:10095000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 -:10096000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 -:10097000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 -:10098000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 -:10099000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 -:1009A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 -:1009B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 -:1009C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 -:1009D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 -:1009E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 -:1009F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 -:100A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 -:100A1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 -:100A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 -:100A3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 -:100A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 -:100A5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 -:100A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 -:100A7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 -:100A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 -:100A9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 -:100AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 -:100AB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 -:100AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 -:100AD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 -:100AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 -:100AF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 -:100B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 -:100B1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 -:100B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 -:100B3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 -:100B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 -:100B5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 -:100B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 -:100B7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 -:100B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 -:100B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 -:100BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 -:100BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 -:100BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 -:100BD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 -:100BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 -:100BF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 -:100C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 -:100C1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 -:100C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 -:100C3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 -:100C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 -:100C5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 -:100C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 -:100C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 -:100C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 -:100C9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 -:100CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 -:100CB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 -:100CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 -:100CD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 -:100CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 -:100CF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 -:100D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 -:100D1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 -:100D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 -:100D3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 -:100D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 -:100D5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 -:100D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 -:100D7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 -:100D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 -:100D9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 -:100DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 -:100DB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 -:100DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 -:100DD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 -:100DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 -:100DF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 -:100E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 -:100E1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 -:100E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 -:100E3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 -:100E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 -:100E5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 -:100E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 -:100E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 -:100E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 -:100E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 -:100EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 -:100EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 -:100EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 -:100ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 -:100EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 -:100EF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 -:100F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 -:100F1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 -:100F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 -:100F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 -:100F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 -:100F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 -:100F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 -:100F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 -:100F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 -:100F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 -:100FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 -:100FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 -:100FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 -:100FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 -:100FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 -:100FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 -:10100000D10020402C100060000000000000000013 -:1010100020100060001000600000000000000000D0 -:10102000000000607031000000000000000001209E -:1010300035100060764B0720764C4FF42A01764A33 -:101040005C64186499639546744A75498A420FD066 -:10105000744B9A420CD2D4430846234423F0030332 -:1010600004330B4450F8041B984242F8041BF9D196 -:101070006D4A6E498A420FD06D4B9A420CD2D443CE -:101080000846234423F0030304330B4450F8041BA5 -:10109000984242F8041BF9D1664A674B9A420BD238 -:1010A000D04311460024034423F0030304331344C4 -:1010B00041F8044B8B42FBD1604A4FF47001604B06 -:1010C000116003F530715F4A43F8042F9942FBD158 -:1010D0005D4B80215D4A03F8011B9342FBD15C4CC0 -:1010E0004FF080375B4E4FF0FF32DFF8A8A10025AC -:1010F000DFF8A491DFF8A481574B4549C3F800A05D -:10110000C4F80471C4F80091C4F8F470C4F8F08015 -:10111000F36923F07F0343F04003F361736A23F024 -:101120007F0343F0400373628A66CA660A674A67B0 -:1011300000F0B6F8494A6320494B4A49106003223F -:101140001D60CAF8381043F8082C4749474A4848F8 -:10115000C3F8082D0B68474A43F08073CAF83C0077 -:1011600045480B601368454943F001031360036869 -:101170000B6000F0E5F8C4F804714148C4F8009130 -:10118000C4F8F470C4F8F08000F03AFA00BF00BF71 -:1011900000BF00BFF16E3B4A41F440513A4BF1664B -:1011A0001560C2F80851C2F81851C2F82851C2F8A7 -:1011B00038519A6BD20708D442F615623349596503 -:1011C0001A659A6B42F001029A632F4A304C936879 -:1011D00043F00113936000F01BFA2368132BFCD932 -:1011E00000F05CF900F0D0F900F016FA00F0DAF83F -:1011F00000F0FEF92368B3F5967FFBD300F0FCF90D -:1012000000F00EFA00F018FA00F012FAFAE700BF48 -:1012100000C00A40ABAAAAAA008007200000000074 -:10122000501600605017000000000020A42D006040 -:10123000D0030020D0030020C032002088ED00E061 -:10124000FC0F00201D05000000E400E0A0E400E029 -:1012500000800D4000C00F4008ED00E014E000E009 -:1012600018E000E095100000FCED00E000002020F8 -:1012700099110000001000E0041000E0A40D00200F -:101280000046C3230040084000400D400000C05607 -:10129000A80D0020001000201B1018200C0D1113A9 -:1012A000F0B5194A0021194B4FF0100E18480124CF -:1012B000184E194D0160194FC2F800E01E6015600C -:1012C000174E184D1F601660174F1D60174E184DB2 -:1012D00017601E60174F1560174E184D1F6016607F -:1012E0001D600460BFF34F8FBFF36F8FC3F8B01161 -:1012F000BFF34F8FBFF36F8F52F8883C43F44033F6 -:1013000042F8883CF0BD00BF9CED00E0A0ED00E09D -:1013100094ED00E0250008031100200021000207E1 -:1013200012000020250008131300202027000B13B3 -:101330001400004033001013150000602F000B074D -:10134000F0B4174A40274FF480314FF480564FF4E1 -:1013500000554FF4404443F24200136913F0020F6A -:1013600006D0946151619061136913F0020FF8D1B6 -:1013700013F4005F01D15561EFE713F4805F01D1F1 -:101380005661EAE7002BE8DA13F4803F01D091615F -:10139000E3E75B0601D45761DFE7F0BC704700BFAD -:1013A00000800D40364A03203649F3EE096A13687F -:1013B00023F00103F0B51360C2F89000D1F8E030DB -:1013C000DFF8D4E0DCB2C3F30B202F4FC0EB135394 -:1013D00007EE904AA4F15501CEF80040B8EEE77A46 -:1013E00003EB830407EE900A03FB01F13B6003EB80 -:1013F0008313B8EEE75A07EE901A091B77EE666A78 -:10140000B8EE677A214D07EE901A0B44C5ED006ADD -:10141000F8EE677A1E4EC7EE265A1E4930601068F5 -:1014200087EEA66A07EE903AF8EE677A87EEA67A1C -:1014300075EE855A76EE056AFCEEE55AFCEEE66A34 -:1014400015EE903A40EA035316EE900A77EE057ACD -:10145000136001EA0041D2F81031FCEEE77A0B4349 -:10146000C2F8103117EE903AD2F81011C3F30B0303 -:101470000B43C2F81031136843F002031360F0BD50 -:1014800080810D4000441F40F8030020F403002039 -:10149000FC0300200000FF0FF0030020304B40F65B -:1014A000617270B5C3F8202140F2044500F0ACF839 -:1014B0002C492D48D1F880202C4C42F003022C4BB3 -:1014C000C1F88020C0F86051226813401BB9D0F8E1 -:1014D000A8319A071AD0244B4FF00041234A516398 -:1014E0001A46D3F8401141F00201C3F84011D2F876 -:1014F00040319B07FBD44FF400301E491B4B4FF08B -:101500000042086019209A6300F09AF81A4D0022F0 -:10151000164B4FF08041144C0A26996328461A60F6 -:101520001146C4F8A8614FF4207200F07DF84FF422 -:1015300081064FF4800040F24313104A10492E6098 -:101540002864C4F85851C2F80412C4F848310D4A4E -:101550004FF4003101231160C4F8403170BD00BF69 -:1015600000800D4000C00F4000002E4000900D4054 -:10157000001C1E008CE200E0003000200010002063 -:10158000F90600000CE100E0114B1249D86E0A4642 -:1015900040F4403030B4D86640F2B765D86EA0242D -:1015A00040F44070D8664D648C64936C1B06FCD488 -:1015B000094B40F2B760A021064A58649964936CC5 -:1015C00013F08003FBD1054A137030BC704700BF95 -:1015D00000C00F4000400C4000800C40A10D0020D6 -:1015E000F8B500BFF8BC08BC9E467047FFFFFFFF80 -:1015F0005FF800F0390500005FF800F055160000B4 -:101600005FF800F0D90100005FF800F0F90D00006C -:101610005FF800F0350500005FF800F06913000086 -:101620005FF800F0010100005FF800F0A51600006F -:101630005FF800F0B91100005FF800F0050100004C -:101640005FF800F05912000045000000FFFFFFFFA7 -:10165000000000000000000000000000000000008A -:10166000000000000000000000000000000000007A -:1016700010B5054C237833B9044B13B10448AFF3CC -:1016800000800123237010BDD00300200000000063 -:1016900054170000084B10B51BB108490848AFF3B8 -:1016A00000800848036803B910BD074B002BFBD02E -:1016B000BDE81040184700BF00000000D403002020 -:1016C00054170000D00300200000000008B5174B9D -:1016D0000121187800F00AFA154B0121187800F062 -:1016E00005FA144B0121187800F000FA124B012181 -:1016F000187800F0FBF9114B0121187800F0F6F989 -:101700000F4B0121187800F0F1F90E4B00211878E9 -:1017100000F0ECF90C4B0021187800F0E7F90B4BC6 -:1017200000211878BDE8084000F0E0B9F40200207C -:10173000FC0200200003002010030020080300200A -:10174000F8020020EC030020EC020020F002002050 -:10175000FFF7BCBF2C4A2D4B2DE9F04714682C4AEB -:10176000DFF8B8A012685746DFF8B490294EDFF8CA -:10177000B480294D93FBF4F393FBF2F4012199F823 -:10178000000000F0ADF9DAF800103268A5FB023273 -:10179000920C04FB02F2DAF800305B1A9A42FAD893 -:1017A000012198F8000000F09BF939683268A5FB28 -:1017B0000232920C04FB02F2DAF800305B1A9A4211 -:1017C000FAD8002199F8000000F08AF939683268E7 -:1017D000A5FB0232920C04FB02F2DAF800305B1A2D -:1017E0009A42FAD8002198F8000000F079F9396897 -:1017F0003268A5FB0232920C04FB02F2DAF80030E8 -:101800005B1A9A42FAD8B9E70C03002000879303C9 -:10181000040300201803002083DE1B43041000E0B3 -:1018200008030020F80200208C4A8D4B90422DE9DD -:10183000F0438C4D5C699969EF681DD98A4B9842D9 -:1018400040F20181894B40F22766DFF860E20344F1 -:10185000874D1A0AAEFB0232D30903EB830303EB75 -:10186000830202F2E243B34228BF3346A3F5487332 -:10187000A5FB0336F60804E07E4EB04294BF062670 -:101880000E26774A07F01F0ED2F88030B64543F097 -:10189000C003C2F880300AD2724B27F01F071A46E5 -:1018A0003743DF601368002BFCDA07F01F0E14F0DB -:1018B00000732ED1704D714AD5F810C015460CEA50 -:1018C0000202AA420ABF4FF0C0534FF480520022D6 -:1018D00084EA030515F0605F06D024F0605403F03D -:1018E00060535F4D1C436C6181EA020313F4405F57 -:1018F00008D05B4B21F4405111431A469961936C17 -:101900001D07FCD444F00074554A5461936C990649 -:10191000FCD401215A4D0A4601FB02F300FB03F3FC -:10192000AB4209D8072A00F28480013201FB02F39E -:1019300000FB03F3AB42F5D95248534D1844A5FBC5 -:101940000030030D6C2B79D8352B7ED8DFF8608101 -:1019500036234E48DFF820C14D4DDCF80090B0FB37 -:10196000F2F009EA05054545B0FBF1F00BD043F470 -:1019700000534FF480586546CCF80080CCF8003016 -:101980002B68002BFCDADFF8D8C0013ADCF8103005 -:1019900003F00703934207D002F007026546CCF834 -:1019A0001020AB6CDB03FCD40139890284EA01030B -:1019B00013F4E05F0AD02A4B24F4E05401F4E05120 -:1019C0001A460C435C61936C9907FCD4314B324945 -:1019D0000344DB09A1FB0331090B042928BF0421BF -:1019E0004B1E1B0284EA030212F4407F06D024F44B -:1019F000407403F440731A4A1C435461184B24F09A -:101A000000741A465C61936C9B06FCD4B0FBF1F148 -:101A1000224A7645224B1060196008D2114B27F0FC -:101A20001F071A463743DF601368002BFCDABDE856 -:101A3000F083042980D8013101226DE7DFF874803A -:101A40006C23184886E712261BE71748DFF86880E2 -:101A500000FB03F043EA08087CE700BF00A4781FFE -:101A600000C00F40000008400046C32300BA3CDC21 -:101A70001F85EB5100366E0100800D404030008024 -:101A8000FFB19F26808D5B00819F5E1600B29F266E -:101A90007F3001807FD1F0089F10E50018030020FF -:101AA0001403002000643F4D001BB70023B24C001C -:101AB000362000806C200080002000800001074B51 -:101AC0001A181B58D2685868104202D011B9C3F8CE -:101AD00088207047C3F88420704700BF00000020B2 -:101AE000272801D8FFF7EABF704700BF27281CD876 -:101AF00000011A4A012902EB0003105810B415D056 -:101B0000042913D0DC68426822EA040242609A6821 -:101B1000E9B102291ED003295B685DF8044B0CBFB4 -:101B20000F491049116015221A607047DA680129BF -:101B3000446842EA040242609A6808D040F63801DC -:101B400011605B6815225DF8044B1A6070473821FC -:101B50001160F6E704491160F3E700BF00000020C0 -:101B6000383001003800010038F0010004207146CF -:101B7000084203D0EFF3098000F008B8EFF30880C3 -:101B800000F004B8704700BF704700BF1B4B052131 -:101B90001B4A382030B5C2F848110821C2F8380372 -:101BA00083B05A68174C0A4317485A60C3F8841028 -:101BB000C3F888102368834202D91448FFF734FE23 -:101BC0000E4D08240020124A1249C5F884400190A5 -:101BD000019B934205D8019B01330193019B9342E2 -:101BE000F9D9C5F888400190019B8B42EDD8019B43 -:101BF00001330193019B8B42F9D9E6E700C01B40FA -:101C000000801F4018030020FF45C32300A3E111FB -:101C10003F420F003F548900836B30B41BB15368BF -:101C200043F40043536072B6446B9CB1104B226086 -:101C3000D3F8B0410C4217D1D3F8404144F480446A -:101C4000C3F84041D3F8B851D3F840416404F3D508 -:101C5000294209D10023064C8260C360D4F8B03118 -:101C60001943C4F8B0110263426362B630BC7047D6 -:101C700000002E4038B50546036B06E0AA6B1C68D1 -:101C800090476A6B2346944208D0184633B1012B23 -:101C900004D05A681206F1D52B6338BD00232B639C -:101CA0006B6338BDF0B5F1B9224C23490020234BBA -:101CB00001228025A1600A601A464D60E060D3F8D9 -:101CC000BC41886044F001141D4DC3F8BC41D3F8F9 -:101CD000B01141F00101C3F8B0112860D2F8B03161 -:101CE000002BFBD1F0BD0904164B144D0126114CFD -:101CF00041F0800100221E60596000F5805CE264C2 -:101D000000F5005EA36400F54057D5F8B01100F56A -:101D100080462A46986041F48031C3F80CC0C3F86D -:101D200010E05F619E61C5F8B011D2F8B031002BB0 -:101D3000FBD1BAE7003000202020002000002E4018 -:101D40000C040020002000202DE9F04FBB4C83B094 -:101D5000D4F8448118F0010FC4F844815ED0D4F85F -:101D6000AC31002B55D04FF00119DFF8F0B2264608 -:101D7000B34FCA46B96AFA6AC4F8AC31D4F84031F4 -:101D800043F40053C4F84031D4F840319D04F5D5F4 -:101D9000D6F8403123F40053C6F84031C6F8B4A158 -:101DA000D4F8B43113F00113FAD188B240F281654E -:101DB000CBF80030A84200F29680B0F5D06F80F0EA -:101DC000D881B0F5817F00F0578100F2D58080285E -:101DD00000F02681822840F0C78092B202F07F0195 -:101DE000072900F2C18089009648974D0844016890 -:101DF00010062B706B7040F1E581C90301D50123FA -:101E00002B7002219048FFF74DFFD4F8AC31002B26 -:101E1000B0D18A4AD2F8BC31002B44D118F0400F1F -:101E200018D0864BD3F8AC111A46C3F8AC11D3F8CE -:101E3000BC11C3F8BC11D2F8B041804B002CFAD1D0 -:101E40004FF0FF32C3F8B421D3F8843100F074FBB3 -:101E50007E4B1C6018F0807F03D07D4B1B6803B164 -:101E6000984718F0007F03D07A4B1B6803B198475E -:101E700018F0040F02D0714BD3F884316F4BD3F8B4 -:101E8000482112060CD518F0800F09D072490A7843 -:101E9000002A00F08E81531EDBB20B7003B9FBBE2B -:101EA00003B0BDE8F08F6D49C2F8BC310868034249 -:101EB00040F0CC81654A14681C40AFD0630700F144 -:101EC000E281670300F1EF81260700F1E881250335 -:101ED00000F1E181E00600F1DA81E1029ED560487F -:101EE000FFF7C8FE9AE742F22105A84238D06FD822 -:101EF000B0F5086F00F02F81B0F5106F34D1C1F349 -:101F00000741584A584811705849594A0193C6F830 -:101F1000C801C6F8CC11C6F8D02100F00FFB554A15 -:101F2000019B80210120FB6410605160D6F8BC1138 -:101F3000936041F00111BA64C6F8BC11D6F8B02123 -:101F400042F48032C6F8B021444A1360D4F8B0316C -:101F5000002BFBD1D4F8AC31002B7FF40BAF58E74A -:101F6000100C072800F03281C4F8C091D4F8AC31CD -:101F7000002B7FF4FFAE4CE740F20235A84200F0A0 -:101F8000B780B0F5A06FEFD13A4A80200125FB64FD -:101F900050601560D6F8BC01936040F00113BA643C -:101FA000C6F8BC31D6F8B03143F48033C6F8B0314E -:101FB000D4F8B031002BFBD10B0C5B0643F08073DF -:101FC000C6F85431D4F8AC31002B7FF4D3AE20E7FF -:101FD00042F22123984200F0828042F2213398425B -:101FE000C2D1244B01218022196000215A60D4F80B -:101FF000BC21BB6442F001129960F964C4F8BC21B1 -:10200000D4F8B03143F48033C4F8B031D4F8B031EF -:10201000002BFBD1D4F8AC31002B7FF4ABAEF8E64B -:10202000094A0221104613705370FFF73BFED4F8A3 -:10203000AC31002B7FF49EAEEBE600BF00002E40DB -:1020400000300020C0012E402004002004040020A5 -:102050000004002008040020100400200C040020CC -:1020600040320020300400200200CC00C8000200F2 -:102070000200C8002020002092B202F07F03072B4C -:102080003FF672AF12F0800F4FEA8303884A4FF099 -:1020900001011A44136814BF23F4803323F00103B1 -:1020A00013608022834B196000215A60D4F8BC2150 -:1020B000BB6442F001129960F964C4F8BC21D4F801 -:1020C000B03143F48033C4F8B031D4F8B031002BD0 -:1020D000FBD1D4F8AC31002B7FF44CAE99E6764BB3 -:1020E000C1F30741754A1868754B1060197078E79D -:1020F00092B202F07F03072B3FF636AF12F0800F4B -:102100004FEA83036A4A4FF001011A44136814BF6F -:1021100043F4803343F0010313608022654B196060 -:1021200000215A60D4F8BC21BB6442F001129960CE -:10213000F964C4F8BC21D4F8B03143F48033C4F856 -:10214000B031D4F8B031002BFBD1D4F8AC31002B36 -:102150007FF410AE5DE65B4A01215B4B12781846B6 -:102160001A70FFF79FFDD4F8AC31002B7FF402AE5C -:102170004FE6564B586800283FF4F6AE090C1FFA9C -:1021800082FE04E00C33586800283FF4EDAE1D8851 -:102190008D42F7D15D887545F4D1090A120C0329E7 -:1021A0000CBF01781989914228BF1146FFF77AFDCB -:1021B0002BE6D3F8482122F08002C3F8482103B06F -:1021C000BDE8F08FCA077FF51CAE18E6404D012030 -:1021D000FB6029603F4B4049186059603F49D6F881 -:1021E000B0016A6001F5005E40F00102A1F5005007 -:1021F00001F58055BB609860A1F58050D860C6F8A5 -:10220000B02119615D61C3F818E0D4F8B031002B3A -:10221000FBD1284A012048F28001FB6410604FF492 -:1022200080305160D6F8BC11936041F00113BA645C -:10223000C6F8BC31D6F8B0310343C6F8B031CBF89C -:102240000000D4F8B031002BFBD1DEE5204C42F287 -:102250002100002524880D6084427FF42BAE2049A4 -:10226000204C03C90D0C86282060A180A5717FF445 -:1022700021AED2F8481150241B4841F08001C2F829 -:102280004811047016E61948FFF7F4FC19E61848DF -:10229000FFF7F0FC21E61748FFF7ECFC1AE61648BA -:1022A000FFF7E8FC13E61548FFF7E4FC0CE600BF77 -:1022B000C0012E4020200020A80D002088320020E0 -:1022C000800D002030040020200400208002002027 -:1022D000180400200020002080000700282400208F -:1022E000280400208032002010040020003100204B -:1022F00000320020C0310020803100204031002019 -:10230000002AA0F102022DE9F04714BF00274FF088 -:102310000057022A01D9BDE8F0874FEAC01ADFF85A -:1023200040900D4604460AEB0906002140229846DB -:10233000304600F0DFFC012047EA05414AF8091069 -:10234000C6F83880B060B8F1000FE4D0034BA0406D -:102350001C6820431860BDE8F08700BF040400201B -:1023600000300020002AA0F102022DE9F04714BF3E -:1023700000274FF00057022A01D9BDE8F08740221C -:10238000C501DFF8449088461544002104461E46E6 -:1023900005EB090A504600F0ADFC012247EA08416E -:1023A00045F80910CAF83860CAF80820002EE4D0B1 -:1023B00004F11000034B8240186802431A60BDE824 -:1023C000F08700BF04040020003000201204816068 -:1023D000C36142F08002F0B44260012701F58056EB -:1023E00001F5005501F5405401F580420760C660D3 -:1023F000056144618261F0BC704700BF831E022BFF -:1024000000D9704730B4064B00F1100401250A468C -:1024100003EBC01005FA04F130BCFFF7FDBB00BFB1 -:1024200040300020831E022B00D9704710B4054BAA -:1024300001240A4604FA00F103EBC0105DF8044BD6 -:10244000FFF7EABB00300020124A134BD2F82002FB -:1024500020F07F40984210B584B002D800EB800095 -:1024600040000E4C01A90A2200F07EFA01A90023C7 -:10247000204611F8012B01333AB10A2B20F8022F24 -:10248000F7D11623237004B010BD5B00DBB22370BC -:1024900004B010BD00441F407F969800B403002094 -:1024A0004368C269C3F30E43054930B4C3F1400326 -:1024B000044C002521F8123024F8125030BC70472B -:1024C000000C0020F80B0020F8B5154B1B783BB929 -:1024D00003F0FF04134B1B7813B1134D2A8802B984 -:1024E000F8BD124F2346124EC2F58072397811485A -:1024F00006EB411600EB01213046FFF767FF31463E -:102500000420FFF77BFF3B780133DBB2062B98BF3B -:102510003B704FF0000388BF3C702B80F8BD00BFBC -:10252000340B002030040020800C0020350B0020EC -:10253000A00C002034040020704700BF0021E022DE -:102540002048F8B50C46204E204D00F0D3FB204F1C -:102550002146204B6022347028461F4E1C8000F01C -:10256000C9FB23462246102102203C60BC80346017 -:10257000B480FFF7F7FE2246184B40210320FFF7F7 -:10258000BFFE2346224640210420FFF7EBFE2346F0 -:10259000402228461249FFF719FF29460320FFF77A -:1025A00041FF104B4A22104910480860C3F884408C -:1025B000C3F88020D3F8482142F08072C3F8482144 -:1025C000F8BD00BFA00C0020350B0020200C00201F -:1025D000000C0020800C0020F80B0020510E0000A1 -:1025E000380B002000002E4000040020790E00006F -:1025F000024A034B10881B88C01A7047000C002049 -:10260000F80B002010B4EFF3108272B6437F33B999 -:10261000017F012908D0032910D00123437702B993 -:1026200062B65DF8044B7047114C2168A1B11149A5 -:1026300043610B68086083615861EEE70E4C2168C6 -:1026400081B10E4943610B680860836158610C4B8E -:102650004FF080511960E0E7064B416181612060D5 -:102660001860DAE7054B4161816120601860EEE790 -:10267000940D0020900D0020840D0020880D002076 -:1026800004ED00E010B4047F4160022CC26003D06E -:102690005DF8044BFFF7B6BF83685DF8044B18473D -:1026A00070B5EFF3108172B60C4C23688BB10C4EF1 -:1026B00000255A6922607AB1956101B962B65D77E9 -:1026C00018469B689847EFF3108172B62368002B79 -:1026D000EFD101B962B670BD3260EEE7840D002023 -:1026E000880D0020FFF7DCBF184A30B41468002CB6 -:1026F00028D0036821688B420FD2CB1A0021846056 -:10270000C1602360E0601060022330BC0375704735 -:102710000360144611688B4208D3A2685B1A002A32 -:10272000F6D18260C4600360A060EDE7D568CB1A83 -:1027300082600222C560E060C16888602360027523 -:1027400030BC70478460C4601060DDE78C0D0020F1 -:10275000F8B5224E34682CB32368002B3AD11D46BD -:102760001F4F04E03468ECB12368002B32D1A3681A -:1027700003B1DD6020693360036825751B68BB42C7 -:1027800021D1037F4560022BC46020D0FFF73AFFC0 -:102790006368002BE6D023602046FFF7A5FF34686E -:1027A000002CE1D1EFF3108372B60E4A00211068BD -:1027B000116003B962B628B18468FFF795FF20461F -:1027C0000028F9D1F8BD224600219847E0E7836848 -:1027D0009847DDE7013B2360E4E700BF8C0D002054 -:1027E000351000009C0D0020044A054B1168054A75 -:1027F0001960136801331360FFF7AABF041000E0EB -:10280000A40D0020A80D002070B5214C237883B9B9 -:10281000204B01221B7822701BBB1F4B1B78002B07 -:1028200029D11E4B00211A68217012B1EFF30582E5 -:1028300002B170BDEFF3108072B61A68F2B1184C95 -:102840002178D9B90126556926701D60D5B1A961D5 -:1028500000B962B6002593681046557798472570F1 -:1028600070BDFFF7C5FE0028D7D000F015FA0A4B5F -:102870001B78002BD5D000F0FBF9D2E70028D8D187 -:1028800062B670BD074B1D600028E3D1E1E700BFD1 -:10289000A00D0020CA030020C80D0020940D0020C8 -:1028A000980D0020900D0020002852D02DE9F04F07 -:1028B000814683B0274C0120274D284E54E8003F25 -:1028C0002A68316844E80003002BF7D1244F4FF405 -:1028D0007A7E2448D7F800C0BB4607F1C647036894 -:1028E000C1EB0C0107F5DE1707F67F67A7FB03C3F3 -:1028F000BA4601279B0CB1FBF3F30EFB023854E8F8 -:10290000003F2A68316844E80073002BF7D1DBF8F8 -:1029100000C04FF47A7E03680EFB02F2C1EB0C019B -:10292000AAFB033EC8EB02034FEA9E42B1FBF2F161 -:10293000CA18B2F57A7F07D3B9F1010908F57A7898 -:10294000DDD103B0BDE8F08F0190FFF75DFF019886 -:10295000D5E770478C320020A80D0020A40D002080 -:10296000041000E018030020F0B44E1E0025374686 -:1029700000E00135B0FBF2F302FB130000F1370475 -:10298000092800F13000E4B298BFC4B2184607F835 -:10299000014F002BEDD14A1953704DB1013316F898 -:1029A000014F1778E81A3770834202F80149F5DBC6 -:1029B0000846F0BC704700BFA4484FF00F0CA44B72 -:1029C000826F42F47F02F0B582670025D0F8802044 -:1029D0004FF470469F4C4FF4604E29464FF4806789 -:1029E00014432A46C0F88040A3F88C6148F2B82608 -:1029F000A3F88EC1A3F89051B3F8880180B240F0DB -:102A0000F000A3F8880101EB4100914B0131002552 -:102A100040011C4604290344A3F804E0DF805A84E3 -:102A20001A865A805A81DE815A82DA825A83DA8380 -:102A3000E9D1B4F888014FF00F0C874B4FF4704682 -:102A400080B229464FF460472A4640EA0C004FF412 -:102A5000806EA4F88801B4F8880180B240F47060F8 -:102A6000A4F88801A3F88C6148F2B826A3F88EC1B7 -:102A7000A3F89051B3F8880180B240F0F000A3F8B9 -:102A8000880101EB4100744B0131002540011C46D7 -:102A9000042903449F80A3F806E05A841A865A80CA -:102AA0005A81DE815A82DA825A83DA83E9D1B4F814 -:102AB00088014FF00F0C694B4FF4704680B22946E5 -:102AC0004FF460472A4640EA0C004FF4806EA4F8A9 -:102AD0008801B4F8880180B240F47060A4F88801DD -:102AE000A3F88C6148F2B826A3F88EC1A3F89051E0 -:102AF000B3F8880180B240F0F000A3F8880101EB40 -:102B00004100564B0131002540011C460429034475 -:102B10009F80A3F806E05A841A865A805A81DE8183 -:102B20005A82DA825A83DA83E9D1B4F888014FF005 -:102B30000F0C4B4B4FF4704780B229464FF4604660 -:102B40002A4640EA0C004FF4806EA4F88801B4F8DD -:102B5000880180B240F47060A4F88801A3F88C71F9 -:102B600048F2B827A3F88EC1A3F89051B3F88801B2 -:102B700080B240F0F000A3F8880101EB4100384B2F -:102B8000013140011C46042903449E80A3F806E05D -:102B90005A841A865A805A81DF815A82DA825A838D -:102BA000DA83EAD1B4F888310F27002241F2010616 -:102BB0009BB245F6C05E114643F226053B43A4F89E -:102BC0008831B4F888319BB243F47063A4F888313B -:102BD0005001244B01320344042A99815981DF8139 -:102BE0009E82A3F806E0198019829D81F0D100220F -:102BF0000F2741F2010645F6C055114643F226045F -:102C00005001194B01320344042A99815981DF8113 -:102C10009E82DD80198019829C81F1D100220F27CC -:102C200041F2010645F6C055114643F22604500113 -:102C30000E4B01320344042A99815981DF819E821F -:102C4000DD80198019829C81F1D1F0BD00C00F4058 -:102C500000C03D40000003FC00003E4000403E40FC -:102C600000803E4000C01D4000001E4000401E404D -:102C700038B5074B1C784CB1064D55F8043F002B76 -:102C8000FBD09847631E13F0FF04F6D138BD00BF98 -:102C9000C80D0020A80D0020014B00221A707047BB -:102CA000CA03002070B50F4E0F4D761BB61018BF2B -:102CB000002405D0013455F8043B9847A642F9D1C9 -:102CC0000A4E0B4D761B00F063F8B61018BF0024B7 -:102CD00006D0013455F8043B9847A642F9D170BD9F -:102CE00070BD00BF48160060481600604C160060BA -:102CF0004816006070B4840746D0541E002A41D0A4 -:102D0000CDB2034602E0621EE4B3144603F8015B51 -:102D10009A07F8D1032C2ED9CDB245EA05250F2C00 -:102D200045EA054519D903F110022646103E0F2E3B -:102D300042F8105C42F80C5C42F8085C42F8045C13 -:102D400002F11002F2D8A4F1100222F00F0204F0F6 -:102D50000F041032032C13440DD91E462246043AA8 -:102D6000032A46F8045BFAD8221F22F00302043239 -:102D7000134404F003042CB1C9B21C4403F8011B32 -:102D8000A342FBD170BC704714460346C2E700BFA4 -:102D90005FF800F0E1150060000000000000000096 -:042DA000F8B500BFC3 -:102DA40000000042C8801F40B8821F400800000095 -:102DB40000000042C4801F40B4821F400400000091 -:102DC40000C0004224801F4014821F4010000000F5 -:102DD40000C0004228801F4018821F4020000000CD -:102DE40000C000422C801F401C821F404000000095 -:102DF40000C0004234801F4024821F4000010000B4 -:102E04000040004264811F4054831F4000040000BE -:102E14000040004280811F4070831F400000020078 -:102E2400004000427C811F406C831F400000010071 -:102E34000040004268811F4058831F400008000082 -:102E4400004000423C811F402C831F4001000000D1 -:102E54000040004244811F4034831F4004000000AE -:102E64000040004240811F4030831F4002000000A8 -:102E74000040004248811F4038831F400800000082 -:102E84000000004204811F40F4821F40000004003F -:102E94000000004208811F40F8821F400000080023 -:102EA4000000004218811F4008831F40000080007A -:102EB4000000004214811F4004831F4000004000B2 -:102EC4000000004200811F40F0821F400000020009 -:102ED40000000042FC801F40EC821F400000010003 -:102EE4000000004224811F4014831F40000000049E -:102EF4000000004228811F4018831F400000000882 -:102F0400000000421C811F400C831F400000000190 -:102F14000000004220811F4010831F400000000277 -:102F240000000042EC801F40DC821F4000100000C3 -:102F340000000042F0801F40E0821F40002000009B -:102F44000000004234811F4024831F4000000040E1 -:102F54000000004238811F4028831F400000008089 -:102F64000080004294801F4084821F4000000400BF -:102F740000C0004290801F4080821F4000000080FB -:102F840000800042A8801F4098821F4000008000FB -:102F940000800042A4801F4094821F400000400033 -:102FA400004000426C811F405C831F400010000001 -:102FB40000C0004230801F4020821F40800000007B -:102FC40000800042C8811F40B8831F400080000079 -:102FD40000800042C4811F40B4831F4000400000B1 -:102FE40000800042C0811F40B0831F4000200000C9 -:102FF40000800042BC811F40AC831F4000100000D1 -:1030040000800042D0811F40C0831F4000000200A6 -:1030140000800042CC811F40BC831F40000001009F -:1030240000010000840300201200000000060000DC -:103034001C0300200A0000000002000040030020DE -:10304400430000000007000040030020430000008C -:1030540000030000B0030020000000000103090485 -:103064002803002000000000020309049803002044 -:103074000000000003030904B40300200000000062 -:10308400000000000000000000000000010000003B -:1030940002000000170000001200000016000000EB -:1030A400150000001E0000001300000000200000B6 -:1030B400140000000029DE07007B9A170A060002AC -:1030C4000200004001000000180354006500650080 -:1030D4006E00730079006400750069006E006F0073 -:1030E40009024300020100C0320904000001020287 -:1030F4000100052400100105240101010424020635 -:1031040005240600010705820310001009040100CC -:10311400020A0000000705030240000007058402BC -:10312400400000001201000202000040C0168304A7 -:103134007902010203010000160355005300420006 -:103144002000530065007200690061006C000000FB -:10315400040309040C030000000000000000000048 -:10316400000000000000000000000100000000005A -:040000056000100087 -:00000001FF diff --git a/tools/odrive/tests/encoder_pass_through.ino.hex b/tools/odrive/tests/encoder_pass_through.ino.hex deleted file mode 100644 index 2f0798bf..00000000 --- a/tools/odrive/tests/encoder_pass_through.ino.hex +++ /dev/null @@ -1,792 +0,0 @@ -:0200000460009A -:100000004643464200000156000000000101020084 -:1000100000000000000000000000000000000000E0 -:1000200000000000000000000000000000000000D0 -:1000300000000000000000000000000000000000C0 -:1000400000000000010403000000000000000000A8 -:100050000000200000000000000000000000000080 -:100060000000000000000000000000000000000090 -:100070000000000000000000000000000000000080 -:10008000EB04180A063204260000000000000000FD -:10009000050404240000000000000000000000002F -:1000A0000000000000000000000000000000000050 -:1000B0000604000000000000000000000000000036 -:1000C0000000000000000000000000000000000030 -:1000D00020041808000000000000000000000000DC -:1000E0000000000000000000000000000000000010 -:1000F0000000000000000000000000000000000000 -:10010000D8041808000000000000000000000000F3 -:100110000204180804200000000000000000000095 -:1001200000000000000000000000000000000000CF -:10013000600400000000000000000000000000005B -:1001400000000000000000000000000000000000AF -:10015000000000000000000000000000000000009F -:10016000000000000000000000000000000000008F -:10017000000000000000000000000000000000007F -:10018000000000000000000000000000000000006F -:10019000000000000000000000000000000000005F -:1001A000000000000000000000000000000000004F -:1001B000000000000000000000000000000000003F -:1001C000000100000010000001000000000000001D -:1001D000000001000000000000000000000000001E -:1001E000000000000000000000000000000000000F -:1001F00000000000000000000000000000000000FF -:10020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE -:10021000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE -:10022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE -:10023000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE -:10024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE -:10025000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE -:10026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E -:10027000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E -:10028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E -:10029000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E -:1002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E -:1002B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E -:1002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E -:1002D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E -:1002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E -:1002F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E -:10030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD -:10031000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED -:10032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD -:10033000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD -:10034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD -:10035000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD -:10036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D -:10037000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D -:10038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D -:10039000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D -:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D -:1003B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D -:1003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D -:1003D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D -:1003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D -:1003F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D -:10040000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC -:10041000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC -:10042000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC -:10043000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC -:10044000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC -:10045000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC -:10046000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C -:10047000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C -:10048000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C -:10049000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C -:1004A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C -:1004B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C -:1004C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C -:1004D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C -:1004E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C -:1004F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C -:10050000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB -:10051000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB -:10052000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB -:10053000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB -:10054000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB -:10055000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB -:10056000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B -:10057000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B -:10058000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B -:10059000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B -:1005A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B -:1005B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B -:1005C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B -:1005D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B -:1005E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B -:1005F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B -:10060000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA -:10061000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA -:10062000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA -:10063000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA -:10064000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA -:10065000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA -:10066000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A -:10067000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A -:10068000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A -:10069000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A -:1006A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A -:1006B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A -:1006C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A -:1006D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A -:1006E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A -:1006F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A -:10070000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 -:10071000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 -:10072000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 -:10073000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 -:10074000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 -:10075000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 -:10076000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 -:10077000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 -:10078000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 -:10079000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 -:1007A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 -:1007B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 -:1007C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 -:1007D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 -:1007E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 -:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 -:10080000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 -:10081000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 -:10082000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 -:10083000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 -:10084000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 -:10085000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 -:10086000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 -:10087000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 -:10088000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 -:10089000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 -:1008A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 -:1008B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 -:1008C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 -:1008D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 -:1008E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 -:1008F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 -:10090000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 -:10091000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 -:10092000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 -:10093000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 -:10094000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 -:10095000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 -:10096000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 -:10097000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 -:10098000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 -:10099000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 -:1009A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 -:1009B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 -:1009C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 -:1009D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 -:1009E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 -:1009F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 -:100A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 -:100A1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 -:100A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 -:100A3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 -:100A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 -:100A5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 -:100A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 -:100A7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 -:100A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 -:100A9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 -:100AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 -:100AB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 -:100AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 -:100AD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 -:100AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 -:100AF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 -:100B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 -:100B1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 -:100B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 -:100B3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 -:100B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 -:100B5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 -:100B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 -:100B7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 -:100B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 -:100B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 -:100BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 -:100BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 -:100BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 -:100BD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 -:100BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 -:100BF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 -:100C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 -:100C1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 -:100C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 -:100C3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 -:100C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 -:100C5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 -:100C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 -:100C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 -:100C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 -:100C9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 -:100CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 -:100CB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 -:100CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 -:100CD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 -:100CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 -:100CF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 -:100D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 -:100D1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 -:100D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 -:100D3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 -:100D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 -:100D5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 -:100D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 -:100D7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 -:100D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 -:100D9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 -:100DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 -:100DB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 -:100DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 -:100DD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 -:100DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 -:100DF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 -:100E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 -:100E1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 -:100E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 -:100E3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 -:100E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 -:100E5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 -:100E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 -:100E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 -:100E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 -:100E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 -:100EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 -:100EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 -:100EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 -:100ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 -:100EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 -:100EF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 -:100F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 -:100F1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 -:100F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 -:100F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 -:100F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 -:100F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 -:100F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 -:100F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 -:100F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 -:100F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 -:100FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 -:100FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 -:100FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 -:100FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 -:100FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 -:100FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 -:10100000D10020402C100060000000000000000013 -:1010100020100060001000600000000000000000D0 -:1010200000000060403100000000000000000120CE -:1010300035100060764B0720764C4FF42A01764A33 -:101040005C64186499639546744A75498A420FD066 -:10105000744B9A420CD2D4430846234423F0030332 -:1010600004330B4450F8041B984242F8041BF9D196 -:101070006D4A6E498A420FD06D4B9A420CD2D443CE -:101080000846234423F0030304330B4450F8041BA5 -:10109000984242F8041BF9D1664A674B9A420BD238 -:1010A000D04311460024034423F0030304331344C4 -:1010B00041F8044B8B42FBD1604A4FF47001604B06 -:1010C000116003F530715F4A43F8042F9942FBD158 -:1010D0005D4B80215D4A03F8011B9342FBD15C4CC0 -:1010E0004FF080375B4E4FF0FF32DFF8A8A10025AC -:1010F000DFF8A491DFF8A481574B4549C3F800A05D -:10110000C4F80471C4F80091C4F8F470C4F8F08015 -:10111000F36923F07F0343F04003F361736A23F024 -:101120007F0343F0400373628A66CA660A674A67B0 -:1011300000F0B6F8494A6320494B4A49106003223F -:101140001D60CAF8381043F8082C4749474A4848F8 -:10115000C3F8082D0B68474A43F08073CAF83C0077 -:1011600045480B601368454943F001031360036869 -:101170000B6000F0E5F8C4F804714148C4F8009130 -:10118000C4F8F470C4F8F08000F036FA00BF00BF75 -:1011900000BF00BFF16E3B4A41F440513A4BF1664B -:1011A0001560C2F80851C2F81851C2F82851C2F8A7 -:1011B00038519A6BD20708D442F615623349596503 -:1011C0001A659A6B42F001029A632F4A304C936879 -:1011D00043F00113936000F033FA2368132BFCD91A -:1011E00000F05CF900F0D0F900F022FA00F0DAF833 -:1011F00000F006FA2368B3F5967FFBD300F010FAEF -:1012000000F012FA00F008FA00F016FAFAE700BF50 -:1012100000C00A40ABAAAAAA008007200000000074 -:10122000501600602017000000000020742D0060A0 -:10123000D0030020D0030020C032002088ED00E061 -:10124000FC0F00206102000000E400E0A0E400E0E8 -:1012500000800D4000C00F4008ED00E014E000E009 -:1012600018E000E0D90D0000FCED00E000002020B7 -:10127000DD0E0000001000E0041000E0A40D0020CE -:101280000046C3230040084000400D400000C05607 -:10129000A80D0020001000201B1018200C0D1113A9 -:1012A000F0B5194A0021194B4FF0100E18480124CF -:1012B000184E194D0160194FC2F800E01E6015600C -:1012C000174E184D1F601660174F1D60174E184DB2 -:1012D00017601E60174F1560174E184D1F6016607F -:1012E0001D600460BFF34F8FBFF36F8FC3F8B01161 -:1012F000BFF34F8FBFF36F8F52F8883C43F44033F6 -:1013000042F8883CF0BD00BF9CED00E0A0ED00E09D -:1013100094ED00E0250008031100200021000207E1 -:1013200012000020250008131300202027000B13B3 -:101330001400004033001013150000602F000B074D -:10134000F0B4174A40274FF480314FF480564FF4E1 -:1013500000554FF4404443F24200136913F0020F6A -:1013600006D0946151619061136913F0020FF8D1B6 -:1013700013F4005F01D15561EFE713F4805F01D1F1 -:101380005661EAE7002BE8DA13F4803F01D091615F -:10139000E3E75B0601D45761DFE7F0BC704700BFAD -:1013A00000800D40364A03203649F3EE096A13687F -:1013B00023F00103F0B51360C2F89000D1F8E030DB -:1013C000DFF8D4E0DCB2C3F30B202F4FC0EB135394 -:1013D00007EE904AA4F15501CEF80040B8EEE77A46 -:1013E00003EB830407EE900A03FB01F13B6003EB80 -:1013F0008313B8EEE75A07EE901A091B77EE666A78 -:10140000B8EE677A214D07EE901A0B44C5ED006ADD -:10141000F8EE677A1E4EC7EE265A1E4930601068F5 -:1014200087EEA66A07EE903AF8EE677A87EEA67A1C -:1014300075EE855A76EE056AFCEEE55AFCEEE66A34 -:1014400015EE903A40EA035316EE900A77EE057ACD -:10145000136001EA0041D2F81031FCEEE77A0B4349 -:10146000C2F8103117EE903AD2F81011C3F30B0303 -:101470000B43C2F81031136843F002031360F0BD50 -:1014800080810D4000441F40F8030020F403002039 -:10149000FC0300200000FF0FF0030020304B40F65B -:1014A000617270B5C3F8202140F2044500F0B0F835 -:1014B0002C492D48D1F880202C4C42F003022C4BB3 -:1014C000C1F88020C0F86051226813401BB9D0F8E1 -:1014D000A8319A071AD0244B4FF00041234A516398 -:1014E0001A46D3F8401141F00201C3F84011D2F876 -:1014F00040319B07FBD44FF400301E491B4B4FF08B -:101500000042086019209A6300F072F81A4D002218 -:10151000164B4FF08041144C0A26996328461A60F6 -:101520001146C4F8A8614FF4207200F06DF84FF432 -:1015300081064FF4800040F24313104A10492E6098 -:101540002864C4F85851C2F80412C4F848310D4A4E -:101550004FF4003101231160C4F8403170BD00BF69 -:1015600000800D4000C00F4000002E4000900D4054 -:10157000001C1E008CE200E0003000200010002063 -:101580003D0400000CE100E0114B1249D86E0A4600 -:1015900040F4403030B4D86640F2B765D86EA0242D -:1015A00040F44070D8664D648C64936C1B06FCD488 -:1015B000094B40F2B760A021064A58649964936CC5 -:1015C00013F08003FBD1054A137030BC704700BF95 -:1015D00000C00F4000400C4000800C40A10D0020D6 -:1015E000F8B500BFF8BC08BC9E467047FFFFFFFF80 -:1015F0005FF800F0311200005FF800F09D0F00006E -:101600005FF800F07D0200005FF800F07D1600003A -:101610005FF800F03D0B00005FF800F005010000EE -:101620005FF800F02D1600005FF800F001010000E7 -:101630005FF800F0411300005FF800F0FD0E0000BD -:101640005FF800F07902000045000000FFFFFFFF97 -:10165000000000000000000000000000000000008A -:10166000000000000000000000000000000000007A -:1016700010B5054C237833B9044B13B10448AFF3CC -:1016800000800123237010BDD00300200000000063 -:1016900024170000084B10B51BB108490848AFF3E8 -:1016A00000800848036803B910BD074B002BFBD02E -:1016B000BDE81040184700BF00000000D403002020 -:1016C00024170000D00300200000000008B5174BCD -:1016D0000121187800F0ACF8154B0121187800F0C2 -:1016E000A7F8144B0121187800F0A2F8124B012141 -:1016F000187800F09DF8114B0121187800F098F847 -:101700000F4B0121187800F093F80E4B0021187848 -:1017100000F08EF80C4B0021187800F089F80B4B84 -:1017200000211878BDE8084000F082B8F4020020DB -:1017300000030020040300200C0300200803002005 -:10174000F8020020EC030020EC020020F002002050 -:10175000FFF7BCBF174B70B5187800F063F8164B55 -:101760000646187800F05EF8144B0546187800F02D -:1017700059F8134B04463146187800F04DF8114BD8 -:101780002946187800F048F80F4B2146187800F0E9 -:1017900043F80E4B3146187800F03EF80C4B2946C2 -:1017A000187800F039F80B4B21461878BDE87040E6 -:1017B00000F032B8FC020020EC020020F002002011 -:1017C000F402002000030020040300200C0300208A -:1017D00008030020F80200200001074B1A181B58CC -:1017E000D2685868104202D011B9C3F888207047F7 -:1017F000C3F88420704700BF000000200001054BA3 -:101800001A5819189268CB681A4214BF0120002098 -:10181000704700BF00000020272801D8FFF7DCBF79 -:10182000704700BF272801D8FFF7E8BF00207047A6 -:1018300027281CD800011A4A012902EB000310587E -:1018400010B415D0042913D0DC68426822EA0402DF -:1018500042609A68E9B102291ED003295B685DF8ED -:10186000044B0CBF0F491049116015221A607047D4 -:10187000DA680129446842EA040242609A6808D0A2 -:1018800040F6380111605B6815225DF8044B1A6060 -:10189000704738211160F6E704491160F3E700BF93 -:1018A00000000020383001003800010038F001004D -:1018B00004207146084203D0EFF3098000F008B815 -:1018C000EFF3088000F004B8704700BF704700BF16 -:1018D0001B4B05211B4A382030B5C2F8481108219E -:1018E000C2F8380383B05A68174C0A4317485A6045 -:1018F000C3F88410C3F888102368834202D91448BF -:1019000000F074FE0E4D08240020124A1249C5F85A -:1019100084400190019B934205D8019B01330193C0 -:10192000019B9342F9D9C5F888400190019B8B42F5 -:10193000EDD8019B01330193019B8B42F9D9E6E776 -:1019400000C01B4000801F40C4030020FF45C3238C -:1019500000A3E1113F420F003F548900836B30B474 -:101960001BB1536843F40043536072B6446B9CB19F -:10197000104B2260D3F8B0410C4217D1D3F840414C -:1019800044F48044C3F84041D3F8B851D3F84041FF -:101990006404F3D5294209D10023064C8260C36058 -:1019A000D4F8B0311943C4F8B0110263426362B68F -:1019B00030BC704700002E4038B50546036B06E08A -:1019C000AA6B1C6890476A6B2346944208D018465D -:1019D00033B1012B04D05A681206F1D52B6338BD00 -:1019E00000232B636B6338BDF0B5F1B9224C23495A -:1019F0000020234B01228025A1600A601A464D6019 -:101A0000E060D3F8BC41886044F001141D4DC3F878 -:101A1000BC41D3F8B01141F00101C3F8B011286006 -:101A2000D2F8B031002BFBD1F0BD0904164B144D98 -:101A30000126114C41F0800100221E60596000F522 -:101A4000805CE26400F5005EA36400F54057D5F8C1 -:101A5000B01100F580462A46986041F48031C3F801 -:101A60000CC0C3F810E05F619E61C5F8B011D2F8F8 -:101A7000B031002BFBD1BAE700300020202000203D -:101A800000002E400C040020002000202DE9F04F23 -:101A9000BB4C83B0D4F8448118F0010FC4F84481E2 -:101AA0005ED0D4F8AC31002B55D04FF00119DFF8DF -:101AB000F0B22646B34FCA46B96AFA6AC4F8AC31E6 -:101AC000D4F8403143F40053C4F84031D4F84031E5 -:101AD0009D04F5D5D6F8403123F40053C6F84031C3 -:101AE000C6F8B4A1D4F8B43113F00113FAD188B216 -:101AF00040F28165CBF80030A84200F29680B0F544 -:101B0000D06F80F0D881B0F5817F00F0578100F26E -:101B1000D580802800F02681822840F0C78092B2CC -:101B200002F07F01072900F2C18089009648974D95 -:101B30000844016810062B706B7040F1E581C90301 -:101B400001D501232B7002219048FFF74DFFD4F8F7 -:101B5000AC31002BB0D18A4AD2F8BC31002B44D131 -:101B600018F0400F18D0864BD3F8AC111A46C3F8C2 -:101B7000AC11D3F8BC11C3F8BC11D2F8B041804B02 -:101B8000002CFAD14FF0FF32C3F8B421D3F88431DE -:101B900000F074FB7E4B1C6018F0807F03D07D4BFF -:101BA0001B6803B1984718F0007F03D07A4B1B687D -:101BB00003B1984718F0040F02D0714BD3F8843169 -:101BC0006F4BD3F8482112060CD518F0800F09D0BE -:101BD00072490A78002A00F08E81531EDBB20B7026 -:101BE00003B9FBBE03B0BDE8F08F6D49C2F8BC314C -:101BF0000868034240F0CC81654A14681C40AFD0AD -:101C0000630700F1E281670300F1EF81260700F12D -:101C1000E881250300F1E181E00600F1DA81E102CB -:101C20009ED56048FFF7C8FE9AE742F22105A84218 -:101C300038D06FD8B0F5086F00F02F81B0F5106F75 -:101C400034D1C1F30741584A584811705849594A8C -:101C50000193C6F8C801C6F8CC11C6F8D02100F02F -:101C60000FFB554A019B80210120FB6410605160ED -:101C7000D6F8BC11936041F00111BA64C6F8BC11EA -:101C8000D6F8B02142F48032C6F8B021444A13603D -:101C9000D4F8B031002BFBD1D4F8AC31002B7FF459 -:101CA0000BAF58E7100C072800F03281C4F8C09140 -:101CB000D4F8AC31002B7FF4FFAE4CE740F2023594 -:101CC000A84200F0B780B0F5A06FEFD13A4A80206B -:101CD0000125FB6450601560D6F8BC01936040F0AC -:101CE0000113BA64C6F8BC31D6F8B03143F480337E -:101CF000C6F8B031D4F8B031002BFBD10B0C5B0629 -:101D000043F08073C6F85431D4F8AC31002B7FF423 -:101D1000D3AE20E742F22123984200F0828042F2C3 -:101D200021339842C2D1244B012180221960002125 -:101D30005A60D4F8BC21BB6442F001129960F96486 -:101D4000C4F8BC21D4F8B03143F48033C4F8B031C6 -:101D5000D4F8B031002BFBD1D4F8AC31002B7FF498 -:101D6000ABAEF8E6094A0221104613705370FFF734 -:101D70003BFED4F8AC31002B7FF49EAEEBE600BF07 -:101D800000002E4000300020C0012E402004002022 -:101D90000404002000040020080400201004002097 -:101DA0000C04002040320020300400200200CC004F -:101DB000C80002000200C8002020002092B202F0F9 -:101DC0007F03072B3FF672AF12F0800F4FEA8303B9 -:101DD000884A4FF001011A44136814BF23F480337A -:101DE00023F0010313608022834B196000215A60A5 -:101DF000D4F8BC21BB6442F001129960F964C4F8C4 -:101E0000BC21D4F8B03143F48033C4F8B031D4F8F5 -:101E1000B031002BFBD1D4F8AC31002B7FF44CAEA9 -:101E200099E6764BC1F30741754A1868754B106007 -:101E3000197078E792B202F07F03072B3FF636AFB6 -:101E400012F0800F4FEA83036A4A4FF001011A44EF -:101E5000136814BF43F4803343F0010313608022FE -:101E6000654B196000215A60D4F8BC21BB6442F074 -:101E700001129960F964C4F8BC21D4F8B03143F47C -:101E80008033C4F8B031D4F8B031002BFBD1D4F892 -:101E9000AC31002B7FF410AE5DE65B4A01215B4B59 -:101EA000127818461A70FFF79FFDD4F8AC31002B5A -:101EB0007FF402AE4FE6564B586800283FF4F6AE6A -:101EC000090C1FFA82FE04E00C33586800283FF426 -:101ED000EDAE1D888D42F7D15D887545F4D1090AB4 -:101EE000120C03290CBF01781989914228BF1146B1 -:101EF000FFF77AFD2BE6D3F8482122F08002C3F8E1 -:101F0000482103B0BDE8F08FCA077FF51CAE18E684 -:101F1000404D0120FB6029603F4B404918605960EB -:101F20003F49D6F8B0016A6001F5005E40F0010259 -:101F3000A1F5005001F58055BB609860A1F5805077 -:101F4000D860C6F8B02119615D61C3F818E0D4F813 -:101F5000B031002BFBD1284A012048F28001FB64FC -:101F600010604FF480305160D6F8BC11936041F09E -:101F70000113BA64C6F8BC31D6F8B0310343C6F8D1 -:101F8000B031CBF80000D4F8B031002BFBD1DEE546 -:101F9000204C42F22100002524880D6084427FF409 -:101FA0002BAE2049204C03C90D0C86282060A1804F -:101FB000A5717FF421AED2F8481150241B4841F09E -:101FC0008001C2F84811047016E61948FFF7F4FCC6 -:101FD00019E61848FFF7F0FC21E61748FFF7ECFC7C -:101FE0001AE61648FFF7E8FC13E61548FFF7E4FC8D -:101FF0000CE600BFC0012E4020200020A80D0020CC -:1020000088320020800D00203004002020040020B1 -:10201000800200201804002000200020800007001B -:1020200028240020280400208032002010040020F2 -:102030000031002000320020C0310020803100201B -:1020400040310020002AA0F102022DE9F04714BF20 -:1020500000274FF00057022A01D9BDE8F0874FEA68 -:10206000C01ADFF840900D4604460AEB090600212D -:1020700040229846304600F029FE012047EA0541FB -:102080004AF80910C6F83880B060B8F1000FE4D003 -:10209000034BA0401C6820431860BDE8F08700BFD8 -:1020A0000404002000300020002AA0F102022DE9E3 -:1020B000F04714BF00274FF00057022A01D9BDE8AE -:1020C000F0874022C501DFF844908846154400217E -:1020D00004461E4605EB090A504600F0F7FD0122B2 -:1020E00047EA084145F80910CAF83860CAF80820DC -:1020F000002EE4D004F11000034B82401868024324 -:102100001A60BDE8F08700BF040400200030002002 -:1021100012048160C36142F08002F0B44260012782 -:1021200001F5805601F5005501F5405401F5804256 -:102130000760C660056144618261F0BC704700BF02 -:10214000831E022B00D9704730B4064B00F11004F7 -:1021500001250A4603EBC01005FA04F130BCFFF775 -:10216000FDBB00BF40300020831E022B00D970470A -:1021700010B4054B01240A4604FA00F103EBC01029 -:102180005DF8044BFFF7EABB00300020124A134B06 -:10219000D2F8200220F07F40984210B584B002D8D7 -:1021A00000EB800040000E4C01A90A2200F0C8FBA1 -:1021B00001A90023204611F8012B01333AB10A2B63 -:1021C00020F8022FF7D11623237004B010BD5B0056 -:1021D000DBB2237004B010BD00441F407F9698000E -:1021E000A80300204368C269C3F30E43054930B415 -:1021F000C3F14003044C002521F8123024F812509A -:1022000030BC7047000C0020F80B0020F8B5154BCF -:102210001B783BB903F0FF04134B1B7813B1134D2C -:102220002A8802B9F8BD124F2346124EC2F58072B9 -:102230003978114806EB411600EB01213046FFF7D3 -:1022400067FF31460420FFF77BFF3B780133DBB2A9 -:10225000062B98BF3B704FF0000388BF3C702B806B -:10226000F8BD00BF340B002030040020800C00209B -:10227000350B0020A00C002034040020704700BF64 -:102280000021E0222048F8B50C46204E204D00F0F9 -:102290001DFD204F2146204B6022347028461F4EE2 -:1022A0001C8000F013FD23462246102102203C60D2 -:1022B000BC803460B480FFF7F7FE2246184B402103 -:1022C0000320FFF7BFFE2346224640210420FFF7EC -:1022D000EBFE2346402228461249FFF719FF294604 -:1022E0000320FFF741FF104B4A22104910480860B5 -:1022F000C3F88440C3F88020D3F8482142F08072AC -:10230000C3F84821F8BD00BFA00C0020350B002009 -:10231000200C0020000C0020800C0020F80B002076 -:10232000950B0000380B002000002E400004002018 -:10233000BD0B0000024A034B10881B88C01A70476F -:10234000000C0020F80B002010B4EFF3108272B6DE -:10235000437F33B9017F012908D0032910D001231D -:10236000437702B962B65DF8044B7047114C21689F -:10237000A1B1114943610B68086083615861EEE7C0 -:102380000E4C216881B10E4943610B68086083617E -:1023900058610C4B4FF080511960E0E7064B4161EA -:1023A000816120601860DAE7054B4161816120603E -:1023B0001860EEE7940D0020900D0020840D0020A1 -:1023C000880D002004ED00E010B4047F4160022C71 -:1023D000C26003D05DF8044BFFF7B6BF83685DF8B9 -:1023E000044B184770B5EFF3108172B60C4C23689C -:1023F0008BB10C4E00255A6922607AB1956101B902 -:1024000062B65D7718469B689847EFF3108172B605 -:102410002368002BEFD101B962B670BD3260EEE7E0 -:10242000840D0020880D0020FFF7DCBF184A30B46F -:102430001468002C28D0036821688B420FD2CB1A75 -:1024400000218460C1602360E0601060022330BC22 -:10245000037570470360144611688B4208D3A26865 -:102460005B1A002AF6D18260C4600360A060EDE7C9 -:10247000D568CB1A82600222C560E060C1688860BE -:102480002360027530BC70478460C4601060DDE773 -:102490008C0D0020F8B5224E34682CB32368002B35 -:1024A0003AD11D461F4F04E03468ECB12368002B7D -:1024B00032D1A36803B1DD602069336003682575FC -:1024C0001B68BB4221D1037F4560022BC46020D032 -:1024D000FFF73AFF6368002BE6D023602046FFF742 -:1024E000A5FF3468002CE1D1EFF3108372B60E4AD9 -:1024F00000211068116003B962B628B18468FFF743 -:1025000095FF20460028F9D1F8BD224600219847C2 -:10251000E0E783689847DDE7013B2360E4E700BF1D -:102520008C0D0020790D00009C0D0020044A054B05 -:102530001168054A1960136801331360FFF7AABFD9 -:10254000041000E0A40D0020A80D002070B5214C5F -:10255000237883B9204B01221B7822701BBB1F4BB1 -:102560001B78002B29D11E4B00211A68217012B153 -:10257000EFF3058202B170BDEFF3108072B61A68F6 -:10258000F2B1184C2178D9B90126556926701D6021 -:10259000D5B1A96100B962B6002593681046557798 -:1025A0009847257070BDFFF7C5FE0028D7D000F012 -:1025B0005FFB0A4B1B78002BD5D000F045FBD2E720 -:1025C0000028D8D162B670BD074B1D600028E3D14A -:1025D000E1E700BFA00D0020C8030020C80D0020C7 -:1025E000940D0020980D0020900D00208C4A8D4BFA -:1025F00090422DE9F0438C4D5C699969EF681DD9D3 -:102600008A4B984240F20181894B40F22766DFF8FD -:1026100060E20344874D1A0AAEFB0232D30903EB92 -:10262000830303EB830202F2E243B34228BF334643 -:10263000A3F54873A5FB0336F60804E07E4EB042CE -:1026400094BF06260E26774A07F01F0ED2F8803078 -:10265000B64543F0C003C2F880300AD2724B27F06F -:102660001F071A463743DF601368002BFCDA07F0B8 -:102670001F0E14F000732ED1704D714AD5F810C0A2 -:1026800015460CEA0202AA420ABF4FF0C0534FF4AB -:102690008052002284EA030515F0605F06D024F022 -:1026A000605403F060535F4D1C436C6181EA020388 -:1026B00013F4405F08D05B4B21F4405111431A469C -:1026C0009961936C1D07FCD444F00074554A546121 -:1026D000936C9906FCD401215A4D0A4601FB02F382 -:1026E00000FB03F3AB4209D8072A00F284800132D1 -:1026F00001FB02F300FB03F3AB42F5D95248534D03 -:102700001844A5FB0030030D6C2B79D8352B7ED8EF -:10271000DFF8608136234E48DFF820C14D4DDCF8EC -:102720000090B0FBF2F009EA05054545B0FBF1F079 -:102730000BD043F400534FF480586546CCF800802A -:10274000CCF800302B68002BFCDADFF8D8C0013A57 -:10275000DCF8103003F00703934207D002F00702C1 -:102760006546CCF81020AB6CDB03FCD40139890240 -:1027700084EA010313F4E05F0AD02A4B24F4E05406 -:1027800001F4E0511A460C435C61936C9907FCD448 -:10279000314B32490344DB09A1FB0331090B042906 -:1027A00028BF04214B1E1B0284EA030212F4407F5F -:1027B00006D024F4407403F440731A4A1C43546155 -:1027C000184B24F000741A465C61936C9B06FCD491 -:1027D000B0FBF1F1224A7645224B1060196008D215 -:1027E000114B27F01F071A463743DF601368002B91 -:1027F000FCDABDE8F083042980D8013101226DE7BD -:10280000DFF874806C23184886E712261BE7174808 -:10281000DFF8688000FB03F043EA08087CE700BFAC -:1028200000A4781F00C00F40000008400046C323EA -:1028300000BA3CDC1F85EB5100366E0100800D4074 -:1028400040300080FFB19F26808D5B00819F5E1627 -:1028500000B29F267F3001807FD1F0089F10E500F5 -:10286000C4030020C003002000643F4D001BB700DC -:1028700023B24C00362000806C20008000200080B5 -:10288000002852D02DE9F04F814683B0274C01201B -:10289000274D284E54E8003F2A68316844E8000379 -:1028A000002BF7D1244F4FF47A7E2448D7F800C08C -:1028B000BB4607F1C6470368C1EB0C0107F5DE17FD -:1028C00007F67F67A7FB03C3BA4601279B0CB1FB42 -:1028D000F3F30EFB023854E8003F2A68316844E8FD -:1028E0000073002BF7D1DBF800C04FF47A7E036849 -:1028F0000EFB02F2C1EB0C01AAFB033EC8EB020384 -:102900004FEA9E42B1FBF2F1CA18B2F57A7F07D3C3 -:10291000B9F1010908F57A78DDD103B0BDE8F08F8F -:102920000190FFF713FE0198D5E770478C32002025 -:10293000A80D0020A40D0020041000E0C403002016 -:10294000F0B44E1E0025374600E00135B0FBF2F32F -:1029500002FB130000F13704092800F13000E4B253 -:1029600098BFC4B2184607F8014F002BEDD14A19A1 -:1029700053704DB1013316F8014F1778E81A3770CC -:10298000834202F80149F5DB0846F0BC704700BFFE -:10299000A4484FF00F0CA44B826F42F47F02F0B5B5 -:1029A00082670025D0F880204FF470469F4C4FF48A -:1029B000604E29464FF4806714432A46C0F8804091 -:1029C000A3F88C6148F2B826A3F88EC1A3F8905101 -:1029D000B3F8880180B240F0F000A3F8880101EB61 -:1029E0004100914B0131002540011C46042903445C -:1029F000A3F804E0DF805A841A865A805A81DE8167 -:102A00005A82DA825A83DA83E9D1B4F888014FF026 -:102A10000F0C874B4FF4704680B229464FF4604745 -:102A20002A4640EA0C004FF4806EA4F88801B4F8FE -:102A3000880180B240F47060A4F88801A3F88C612A -:102A400048F2B826A3F88EC1A3F89051B3F88801D4 -:102A500080B240F0F000A3F8880101EB4100744B14 -:102A60000131002540011C46042903449F80A3F83E -:102A700006E05A841A865A805A81DE815A82DA82A6 -:102A80005A83DA83E9D1B4F888014FF00F0C694B0F -:102A90004FF4704680B229464FF460472A4640EA18 -:102AA0000C004FF4806EA4F88801B4F8880180B25D -:102AB00040F47060A4F88801A3F88C6148F2B8264D -:102AC000A3F88EC1A3F89051B3F8880180B240F00A -:102AD000F000A3F8880101EB4100564B01310025BD -:102AE00040011C46042903449F80A3F806E05A8451 -:102AF0001A865A805A81DE815A82DA825A83DA83B0 -:102B0000E9D1B4F888014FF00F0C4B4B4FF47047EC -:102B100080B229464FF460462A4640EA0C004FF442 -:102B2000806EA4F88801B4F8880180B240F4706027 -:102B3000A4F88801A3F88C7148F2B827A3F88EC1D5 -:102B4000A3F89051B3F8880180B240F0F000A3F8E8 -:102B5000880101EB4100384B013140011C4604293A -:102B600003449E80A3F806E05A841A865A805A814C -:102B7000DF815A82DA825A83DA83EAD1B4F8883163 -:102B80000F27002241F201069BB245F6C05E1146B6 -:102B900043F226053B43A4F88831B4F888319BB250 -:102BA00043F47063A4F888315001244B013203448C -:102BB000042A99815981DF819E82A3F806E0198059 -:102BC00019829D81F0D100220F2741F2010645F6BE -:102BD000C055114643F226045001194B01320344FB -:102BE000042A99815981DF819E82DD8019801982B2 -:102BF0009C81F1D100220F2741F2010645F6C05514 -:102C0000114643F2260450010E4B01320344042ABC -:102C100099815981DF819E82DD80198019829C8192 -:102C2000F1D1F0BD00C00F4000C03D40000003FCEA -:102C300000003E4000403E4000803E4000C01D403D -:102C400000001E4000401E4038B5074B1C784CB1B8 -:102C5000064D55F8043F002BFBD09847631E13F038 -:102C6000FF04F6D138BD00BFC80D0020A80D00201C -:102C7000014B00221A707047C803002070B50F4E38 -:102C80000F4D761BB61018BF002405D0013455F83F -:102C9000043B9847A642F9D10A4E0B4D761B00F033 -:102CA00063F8B61018BF002406D0013455F8043B71 -:102CB0009847A642F9D170BD70BD00BF48160060AC -:102CC000481600604C1600604816006070B4840717 -:102CD00046D0541E002A41D0CDB2034602E0621E07 -:102CE000E4B3144603F8015B9A07F8D1032C2ED9FC -:102CF000CDB245EA05250F2C45EA054519D903F162 -:102D000010022646103E0F2E42F8105C42F80C5C72 -:102D100042F8085C42F8045C02F11002F2D8A4F117 -:102D2000100222F00F0204F00F041032032C13449F -:102D30000DD91E462246043A032A46F8045BFAD807 -:102D4000221F22F003020432134404F003042CB1C6 -:102D5000C9B21C4403F8011BA342FBD170BC7047ED -:102D600014460346C2E700BF5FF800F0E1150060BB -:042D7000F8B500BFF3 -:102D740000000042C8801F40B8821F4008000000C5 -:102D840000000042C4801F40B4821F4004000000C1 -:102D940000C0004224801F4014821F401000000025 -:102DA40000C0004228801F4018821F4020000000FD -:102DB40000C000422C801F401C821F4040000000C5 -:102DC40000C0004234801F4024821F4000010000E4 -:102DD4000040004264811F4054831F4000040000EF -:102DE4000040004280811F4070831F4000000200A9 -:102DF400004000427C811F406C831F4000000100A2 -:102E04000040004268811F4058831F4000080000B2 -:102E1400004000423C811F402C831F400100000001 -:102E24000040004244811F4034831F4004000000DE -:102E34000040004240811F4030831F4002000000D8 -:102E44000040004248811F4038831F4008000000B2 -:102E54000000004204811F40F4821F40000004006F -:102E64000000004208811F40F8821F400000080053 -:102E74000000004218811F4008831F4000008000AA -:102E84000000004214811F4004831F4000004000E2 -:102E94000000004200811F40F0821F400000020039 -:102EA40000000042FC801F40EC821F400000010033 -:102EB4000000004224811F4014831F4000000004CE -:102EC4000000004228811F4018831F4000000008B2 -:102ED400000000421C811F400C831F4000000001C1 -:102EE4000000004220811F4010831F4000000002A8 -:102EF40000000042EC801F40DC821F4000100000F4 -:102F040000000042F0801F40E0821F4000200000CB -:102F14000000004234811F4024831F400000004011 -:102F24000000004238811F4028831F4000000080B9 -:102F34000080004294801F4084821F4000000400EF -:102F440000C0004290801F4080821F40000000802B -:102F540000800042A8801F4098821F40000080002B -:102F640000800042A4801F4094821F400000400063 -:102F7400004000426C811F405C831F400010000031 -:102F840000C0004230801F4020821F4080000000AB -:102F940000800042C8811F40B8831F4000800000A9 -:102FA40000800042C4811F40B4831F4000400000E1 -:102FB40000800042C0811F40B0831F4000200000F9 -:102FC40000800042BC811F40AC831F400010000001 -:102FD40000800042D0811F40C0831F4000000200D7 -:102FE40000800042CC811F40BC831F4000000100D0 -:102FF4000001000078030020120000000006000019 -:10300400100300200A000000000200003403002026 -:1030140043000000000700003403002043000000C8 -:1030240000030000A40300200000000001030904C1 -:103034001C03002000000000020309048C0300208C -:103044000000000003030904A8030020000000009E -:10305400000000000000000000000000010000006B -:10306400020000001700000012000000040000002D -:1030740016000000150000001300000014000000FA -:103084000A06000202000040010000001803540078 -:10309400650065006E0073007900640075006900C6 -:1030A4006E006F0009024300020100C032090400EF -:1030B40000010202010005240010010524010101A0 -:1030C40004240206052406000107058203100010EB -:1030D40009040100020A0000000705030240000081 -:1030E40007058402400000001201000202000040B3 -:1030F400C01683047902010203010000160355007F -:103104005300420020005300650072006900610012 -:103114006C000000040309040C030000000000001C -:10312400000000000000000000000000000000009B -:103134000029DE07007B9A17010000000000000050 -:040000056000100087 -:00000001FF diff --git a/tools/odrive/tests/encoder_test.py b/tools/odrive/tests/encoder_test.py index efde608b..723432a6 100644 --- a/tools/odrive/tests/encoder_test.py +++ b/tools/odrive/tests/encoder_test.py @@ -6,79 +6,278 @@ from math import pi import os from fibre.utils import Logger -from test_runner import EncoderTestContext, test_assert_eq, program_teensy +from odrive.enums import * +from test_runner import * -def modpm(val, range): - return ((val + (range / 2)) % range) - (range / 2) -class TestIncrementalEncoder(): +teensy_code_template = """ +void setup() { + pinMode({enc_a}, OUTPUT); + pinMode({enc_b}, OUTPUT); +} - def is_compatible(self, enc_ctx: EncoderTestContext): - return True +int cpr = 8192; +int rpm = 30; - def run_delta_test(self, encoder, true_cps, with_cpr): - encoder.config.cpr = with_cpr +// the loop routine runs over and over again forever: +void loop() { + int microseconds_per_count = (1000000 * 60 / cpr / rpm); - for i in range(100): - now = time.monotonic() - new_shadow_count = encoder.shadow_count - new_count_in_cpr = encoder.count_in_cpr - new_phase = encoder.phase - new_pos_estimate = encoder.pos_estimate - new_pos_cpr = encoder.pos_cpr + for (;;) { + digitalWrite({enc_a}, HIGH); + delayMicroseconds(microseconds_per_count); + digitalWrite({enc_b}, HIGH); + delayMicroseconds(microseconds_per_count); + digitalWrite({enc_a}, LOW); + delayMicroseconds(microseconds_per_count); + digitalWrite({enc_b}, LOW); + delayMicroseconds(microseconds_per_count); + } +} +""" - if i > 0: - dt = now - before - test_assert_eq((new_shadow_count - last_shadow_count) / dt, true_cps, accuracy = 0.05) - test_assert_eq(modpm(new_count_in_cpr - last_count_in_cpr, with_cpr) / dt, true_cps, accuracy = 0.3) - #test_assert_eq(modpm(new_phase - last_phase, 2*pi) / dt, 2*pi*true_rps, accuracy = 0.1) - test_assert_eq((new_pos_estimate - last_pos_estimate) / dt, true_cps, accuracy = 0.3) - test_assert_eq(modpm(new_pos_cpr - last_pos_cpr, with_cpr) / dt, true_cps, accuracy = 0.3) - test_assert_eq(encoder.vel_estimate, true_cps, accuracy = 0.05) - - before = now - last_shadow_count = new_shadow_count - last_count_in_cpr = new_count_in_cpr - last_phase = new_phase - last_pos_estimate = new_pos_estimate - last_pos_cpr = new_pos_cpr - - time.sleep(0.01) +teensy_code_template2 = """ +void setup() { + analogWriteResolution(10); + int freq = 150000000/1024; // ~146.5kHz PWM frequency + analogWriteFrequency({enc_sin}, freq); + analogWriteFrequency({enc_cos}, freq); +} - def run_test(self, enc_ctx: EncoderTestContext, logger: Logger): +int rpm = 60; +float pos = 0; + +void loop() { + pos += 0.001f * ((float)rpm / 60.0f); + if (pos > 1.0f) + pos -= 1.0f; + analogWrite({enc_sin}, (int)(512.0f + 512.0f * sin(2.0f * M_PI * pos))); + analogWrite({enc_cos}, (int)(512.0f + 512.0f * cos(2.0f * M_PI * pos))); + delay(1); +} +""" + +teensy_code_template3 = """ +void setup() { + pinMode({hall_a}, OUTPUT); + pinMode({hall_b}, OUTPUT); + pinMode({hall_c}, OUTPUT); + digitalWrite({hall_a}, HIGH); +} + +int cpr = 90; // 15 pole-pairs. Value suggested in hoverboard.md +int rpm = 60; +int microseconds_per_count = (1000000 * 60 / cpr / rpm); + +void loop() { + digitalWrite({hall_b}, HIGH); + delayMicroseconds(microseconds_per_count); + digitalWrite({hall_a}, LOW); + delayMicroseconds(microseconds_per_count); + digitalWrite({hall_c}, HIGH); + delayMicroseconds(microseconds_per_count); + digitalWrite({hall_b}, LOW); + delayMicroseconds(microseconds_per_count); + digitalWrite({hall_a}, HIGH); + delayMicroseconds(microseconds_per_count); + digitalWrite({hall_c}, LOW); + delayMicroseconds(microseconds_per_count); +} +""" + + +class TestEncoderBase(): + """ + Base class for encoder tests. + TODO: incremental encoder doesn't use this yet. + + All encoder tests expect the encoder to run at a constant velocity. + This can be achieved by generating an encoder signal with a Teensy. + + During 5 seconds, several variables are recorded and then compared against + the expected waveform. This is either a straight line, a sawtooth function + or a constant. + """ + + def run_generic_encoder_test(self, encoder, true_cpr, true_rps): + encoder.config.cpr = true_cpr + true_cps = true_cpr * true_rps + + logger.debug("Recording log...") + data = [] + start = time.monotonic() + encoder.set_linear_count(0) # prevent numerical errors + while time.monotonic() - start < 5.0: + data.append(( + time.monotonic() - start, + encoder.shadow_count, + encoder.count_in_cpr, + encoder.phase, + encoder.pos_estimate, + encoder.pos_cpr, + encoder.vel_estimate, + )) + + data = np.array(data) + + short_period = (abs(1 / true_rps) < 5.0) + reverse = (true_rps < 0) + + # encoder.shadow_count + slope, offset, fitted_curve = fit_line(data[:,(0,1)]) + test_assert_eq(slope, true_cps, accuracy=0.005) + test_curve_fit(data[:,(0,1)], fitted_curve, max_mean_err = true_cpr * 0.01, inlier_range = true_cpr * 0.02, max_outliers = len(data[:,0]) * 0.02) + + # encoder.count_in_cpr + slope, offset, fitted_curve = fit_sawtooth(data[:,(0,2)], true_cpr if reverse else 0, 0 if reverse else true_cpr) + test_assert_eq(slope, true_cps, accuracy=0.005) + test_curve_fit(data[:,(0,2)], fitted_curve, max_mean_err = true_cpr * 0.01, inlier_range = true_cpr * 0.02, max_outliers = len(data[:,0]) * 0.02) + + # encoder.phase + slope, offset, fitted_curve = fit_sawtooth(data[:,(0,3)], pi if reverse else -pi, -pi if reverse else pi, sigma=5) + test_assert_eq(slope / 7, 2*pi*true_rps, accuracy=0.01) + test_curve_fit(data[:,(0,3)], fitted_curve, max_mean_err = true_cpr * 0.01, inlier_range = true_cpr * 0.02, max_outliers = len(data[:,0]) * 0.02) + + # encoder.pos_estimate + slope, offset, fitted_curve = fit_line(data[:,(0,4)]) + test_assert_eq(slope, true_cps, accuracy=0.005) + test_curve_fit(data[:,(0,4)], fitted_curve, max_mean_err = true_cpr * 0.01, inlier_range = true_cpr * 0.02, max_outliers = len(data[:,0]) * 0.02) + + # encoder.pos_cpr + slope, offset, fitted_curve = fit_sawtooth(data[:,(0,5)], true_cpr if reverse else 0, 0 if reverse else true_cpr) + test_assert_eq(slope, true_cps, accuracy=0.005) + test_curve_fit(data[:,(0,5)], fitted_curve, max_mean_err = true_cpr * 0.05, inlier_range = true_cpr * 0.05, max_outliers = len(data[:,0]) * 0.02) + + # encoder.vel_estimate + slope, offset, fitted_curve = fit_line(data[:,(0,6)]) + test_assert_eq(slope, 0.0, range = true_cpr * abs(true_rps) * 0.01) + test_assert_eq(offset, true_cpr * true_rps, accuracy = 0.01) + test_curve_fit(data[:,(0,6)], fitted_curve, max_mean_err = true_cpr * 0.05, inlier_range = true_cpr * 0.05, max_outliers = len(data[:,0]) * 0.02) + + + + +class TestIncrementalEncoder(TestEncoderBase): + + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + for encoder in odrive.encoders: + # Find the Teensy that is connected to the encoder pins and the corresponding Teensy GPIOs + + gpio_conns = [ + testrig.get_directly_connected_components(encoder.a), + testrig.get_directly_connected_components(encoder.b), + ] + + valid_combinations = [ + (combination[0].parent,) + tuple(combination) + for combination in itertools.product(*gpio_conns) + if ((len(set(c.parent for c in combination)) == 1) and isinstance(combination[0].parent, TeensyComponent)) + ] + + yield (encoder, valid_combinations) + + + def run_test(self, enc: EncoderComponent, teensy: TeensyComponent, teensy_gpio_a: int, teensy_gpio_b: int, logger: Logger): true_cps = 8192*-0.5 # counts per second generated by the virtual encoder - # TODO: read teensy config from YAML file - if enc_ctx.num == 0: - hexfile = 'enc0_sim_-4096cps.ino.hex' + + code = teensy_code_template.replace("{enc_a}", str(teensy_gpio_a.num)).replace("{enc_b}", str(teensy_gpio_b.num)) + teensy.compile_and_program(code) + + if enc.handle.config.mode != ENCODER_MODE_INCREMENTAL: + enc.handle.config.mode = ENCODER_MODE_INCREMENTAL + enc.parent.save_config_and_reboot() else: - hexfile = 'enc1_sim_-4096cps.ino.hex' - program_teensy(os.path.join(os.path.dirname(__file__), hexfile), 26, logger) - time.sleep(1.0) # wait for PLLs to stabilize + time.sleep(1.0) # wait for PLLs to stabilize - encoder = enc_ctx.handle + enc.handle.config.bandwidth = 1000 - # The true encoder count and PLL output should be roughly the same. - # At 8192 CPR and 0.5 RPM, the delta because of sequential reading is - # around 3.25 counts. The exact value depends on the connection. - # The tracking error of the PLL is below 1 count. + logger.debug("testing with 8192 CPR...") + self.run_generic_encoder_test(enc.handle, 8192, true_cps / 8192) + logger.debug("testing with 65536 CPR...") + self.run_generic_encoder_test(enc.handle, 65536, true_cps / 65536) + enc.handle.config.cpr = 8192 - #logger.debug("check if count_in_cpr == pos_cpr") - #configured_cpr = 8192 - #encoder.config.cpr = configured_cpr - #expected_delta = true_cps/1200 - #for _ in range(1000): - # first = enc_ctx.handle.axis0.encoder.count_in_cpr - # second = enc_ctx.handle.axis0.encoder.pos_cpr - # test_assert_eq(modpm(second - first, configured_cpr), expected_delta, range=abs(true_cps/500)) - # time.sleep(0.001) - logger.debug("check if variables move at the correct velocity (8192 CPR)...") - self.run_delta_test(encoder, true_cps, 8192) - logger.debug("check if variables move at the correct velocity (65536 CPR)...") - self.run_delta_test(encoder, true_cps, 65536) - encoder.config.cpr = 8192 +class TestSinCosEncoder(TestEncoderBase): + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + gpio_conns = [ + testrig.get_directly_connected_components(odrive.gpio3), + testrig.get_directly_connected_components(odrive.gpio4), + ] + + valid_combinations = [ + (combination[0].parent,) + tuple(combination) + for combination in itertools.product(*gpio_conns) + if ((len(set(c.parent for c in combination)) == 1) and isinstance(combination[0].parent, TeensyComponent)) + ] + + yield (odrive.encoders[0], valid_combinations) + + + def run_test(self, enc: EncoderComponent, teensy: TeensyComponent, teensy_gpio_sin: TeensyGpio, teensy_gpio_cos: TeensyGpio, logger: Logger): + code = teensy_code_template2.replace("{enc_sin}", str(teensy_gpio_sin.num)).replace("{enc_cos}", str(teensy_gpio_cos.num)) + teensy.compile_and_program(code) + + if enc.handle.config.mode != ENCODER_MODE_SINCOS: + enc.parent.unuse_gpios() + enc.handle.config.mode = ENCODER_MODE_SINCOS + enc.parent.save_config_and_reboot() + else: + time.sleep(1.0) # wait for PLLs to stabilize + + enc.handle.config.bandwidth = 100 + + self.run_generic_encoder_test(enc.handle, 6283, 1.0) + + + +class TestHallEffectEncoder(TestEncoderBase): + + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + for encoder in odrive.encoders: + # Find the Teensy that is connected to the encoder pins and the corresponding Teensy GPIOs + + gpio_conns = [ + testrig.get_directly_connected_components(encoder.a), + testrig.get_directly_connected_components(encoder.b), + testrig.get_directly_connected_components(encoder.z), + ] + + valid_combinations = [ + (combination[0].parent,) + tuple(combination) + for combination in itertools.product(*gpio_conns) + if ((len(set(c.parent for c in combination)) == 1) and isinstance(combination[0].parent, TeensyComponent)) + ] + + yield (encoder, valid_combinations) + + + def run_test(self, enc: EncoderComponent, teensy: TeensyComponent, teensy_gpio_a: int, teensy_gpio_b: int, teensy_gpio_c: int, logger: Logger): + true_cpr = 90 + true_rps = -1.0 + + code = teensy_code_template3.replace("{hall_a}", str(teensy_gpio_a.num)).replace("{hall_b}", str(teensy_gpio_b.num)).replace("{hall_c}", str(teensy_gpio_c.num)) + teensy.compile_and_program(code) + + if enc.handle.config.mode != ENCODER_MODE_HALL: + enc.handle.config.mode = ENCODER_MODE_HALL + enc.parent.save_config_and_reboot() + else: + time.sleep(1.0) # wait for PLLs to stabilize + + enc.handle.config.bandwidth = 100 + + self.run_generic_encoder_test(enc.handle, true_cpr, true_rps) + enc.handle.config.cpr = 8192 if __name__ == '__main__': - test_runner.run(TestIncrementalEncoder()) + test_runner.run([ + TestIncrementalEncoder(), + TestSinCosEncoder(), + TestHallEffectEncoder(), + ]) diff --git a/tools/odrive/tests/nvm_test.py b/tools/odrive/tests/nvm_test.py index 99da037f..72ed2061 100644 --- a/tools/odrive/tests/nvm_test.py +++ b/tools/odrive/tests/nvm_test.py @@ -7,17 +7,18 @@ import os import fibre from fibre.utils import Logger -from test_runner import ODriveTestContext, test_assert_eq +from test_runner import * class TestStoreAndReboot(): """ Stores the current configuration to NVM and reboots. """ - def is_compatible(self, odrive: ODriveTestContext): - return True + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + yield (odrive,) - def run_with_values(self, values, odrive: ODriveTestContext, logger: Logger): + def run_with_values(self, odrive: ODriveComponent, values: list, logger: Logger): logger.debug("storing configuration and rebooting...") for value in values: @@ -31,15 +32,15 @@ class TestStoreAndReboot(): odrive.handle = None time.sleep(2) - odrive.make_available(logger) + odrive.prepare(logger) logger.debug("verifying configuration after reboot...") test_assert_eq(odrive.handle.config.brake_resistance, values[-1], accuracy=0.01) - def run_test(self, odrive: ODriveTestContext, logger: Logger): - self.run_with_values([0.5, 1.0, 1.5], odrive, logger) - self.run_with_values([2.5, 3.7], odrive, logger) - self.run_with_values([0.47], odrive, logger) + def run_test(self, odrive: ODriveComponent, logger: Logger): + self.run_with_values(odrive, [0.5, 1.0, 1.5], logger) + self.run_with_values(odrive, [2.5, 3.7], logger) + self.run_with_values(odrive, [0.47], logger) if __name__ == '__main__': test_runner.run(TestStoreAndReboot()) diff --git a/tools/odrive/tests/pwm_input_test.py b/tools/odrive/tests/pwm_input_test.py index e70f8e1e..e601bd72 100644 --- a/tools/odrive/tests/pwm_input_test.py +++ b/tools/odrive/tests/pwm_input_test.py @@ -5,16 +5,37 @@ import time import math import os -import fibre -from fibre.utils import Logger from odrive.enums import errors -from test_runner import ODriveTestContext, test_assert_eq, program_teensy +from test_runner import * -#def modpm(val, lower_bound, upper_bound): -# return ((val - lower_bound) % (upper_bound - lower_bound)) - lower_bound -def modpm(val, range): - return ((val + (range / 2)) % range) - (range / 2) +teensy_code_template = """ +float position = 0; // between 0 and 1 +float velocity = 1; // [position per second] + +void setup() { +{setup_code} +} + +// the loop routine runs over and over again forever: +void loop() { + int high_microseconds = 1000 + (int)(position * 1000.0f); + +{set_high_code} + delayMicroseconds(high_microseconds); +{set_low_code} + + // Wait for a total of 20ms. + // delayMicroseconds() only works well for values <= 16383 + delayMicroseconds(10000 - high_microseconds); + delayMicroseconds(10000); + + position += velocity * 0.02; + while (position > 1.0) + position -= 1.0; +} +""" + class TestPwmInput(): """ @@ -28,8 +49,24 @@ class TestPwmInput(): Note: this test is currently only written for ODrive 3.6 (or similar GPIO layout). """ - def is_compatible(self, odrive: ODriveTestContext): - return True + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + # Find the Teensy that is connected to gpios 1-4 of the ODrive and the corresponding Teensy GPIOs + + gpio_conns = [ + testrig.get_directly_connected_components(odrive.gpio1), + testrig.get_directly_connected_components(odrive.gpio2), + testrig.get_directly_connected_components(odrive.gpio3), + testrig.get_directly_connected_components(odrive.gpio4) + ] + + valid_combinations = [ + (combination[0].parent,) + tuple(combination) + for combination in itertools.product(*gpio_conns) + if ((len(set(c.parent for c in combination)) == 1) and isinstance(combination[0].parent, TeensyComponent)) + ] + + yield (odrive, valid_combinations) def run_delta_test(self, attr, with_min, with_max, timeout = 5.0): rounds_per_s = 1.0 @@ -84,10 +121,16 @@ class TestPwmInput(): test_assert_eq(min_val, with_min, range = step_size) test_assert_eq(max_val, with_max, range = step_size) - def run_test(self, odrive: ODriveTestContext, logger: Logger): + def run_test(self, odrive: ODriveComponent, teensy: TeensyComponent, teensy_gpio1: Component, teensy_gpio2: Component, teensy_gpio3: Component, teensy_gpio4: Component, logger: Logger): # TODO: test each GPIO separately - hexfile = 'pwm_sim.ino.hex' - program_teensy(os.path.join(os.path.dirname(__file__), hexfile), 26, logger) + + setup_code = "\n".join(" pinMode(" + str(gpio.num) + ", OUTPUT);" for gpio in [teensy_gpio1, teensy_gpio2, teensy_gpio3, teensy_gpio4]) + set_high_code = "\n".join(" digitalWrite(" + str(gpio.num) + ", HIGH);" for gpio in [teensy_gpio1, teensy_gpio2, teensy_gpio3, teensy_gpio4]) + set_low_code = "\n".join(" digitalWrite(" + str(gpio.num) + ", LOW);" for gpio in [teensy_gpio1, teensy_gpio2, teensy_gpio3, teensy_gpio4]) + + code = teensy_code_template.replace("{setup_code}", setup_code).replace("{set_high_code}", set_high_code).replace("{set_low_code}", set_low_code) + teensy.compile_and_program(code) + time.sleep(1.0) # wait for PLLs to stabilize logger.debug("Set up PWM input...") @@ -106,15 +149,7 @@ class TestPwmInput(): odrive.handle.config.gpio4_pwm_mapping.min = -20000 odrive.handle.config.gpio4_pwm_mapping.max = 20000 - # Save and reboot - odrive.handle.save_configuration() - try: - odrive.handle.reboot() - except fibre.ChannelBrokenException: - pass # this is expected - odrive.handle = None - time.sleep(2) - odrive.make_available(logger) + odrive.save_config_and_reboot() logger.debug("Check if PWM on GPIO1 works...") self.run_delta_test(odrive.handle.axis0.controller._remote_attributes['input_pos'], -50, 200) diff --git a/tools/odrive/tests/pwm_sim.ino.hex b/tools/odrive/tests/pwm_sim.ino.hex deleted file mode 100644 index efd5bf65..00000000 --- a/tools/odrive/tests/pwm_sim.ino.hex +++ /dev/null @@ -1,801 +0,0 @@ -:0200000460009A -:100000004643464200000156000000000101020084 -:1000100000000000000000000000000000000000E0 -:1000200000000000000000000000000000000000D0 -:1000300000000000000000000000000000000000C0 -:1000400000000000010403000000000000000000A8 -:100050000000200000000000000000000000000080 -:100060000000000000000000000000000000000090 -:100070000000000000000000000000000000000080 -:10008000EB04180A063204260000000000000000FD -:10009000050404240000000000000000000000002F -:1000A0000000000000000000000000000000000050 -:1000B0000604000000000000000000000000000036 -:1000C0000000000000000000000000000000000030 -:1000D00020041808000000000000000000000000DC -:1000E0000000000000000000000000000000000010 -:1000F0000000000000000000000000000000000000 -:10010000D8041808000000000000000000000000F3 -:100110000204180804200000000000000000000095 -:1001200000000000000000000000000000000000CF -:10013000600400000000000000000000000000005B -:1001400000000000000000000000000000000000AF -:10015000000000000000000000000000000000009F -:10016000000000000000000000000000000000008F -:10017000000000000000000000000000000000007F -:10018000000000000000000000000000000000006F -:10019000000000000000000000000000000000005F -:1001A000000000000000000000000000000000004F -:1001B000000000000000000000000000000000003F -:1001C000000100000010000001000000000000001D -:1001D000000001000000000000000000000000001E -:1001E000000000000000000000000000000000000F -:1001F00000000000000000000000000000000000FF -:10020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE -:10021000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE -:10022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE -:10023000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE -:10024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE -:10025000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE -:10026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E -:10027000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E -:10028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E -:10029000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E -:1002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E -:1002B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E -:1002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E -:1002D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E -:1002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E -:1002F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E -:10030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD -:10031000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED -:10032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD -:10033000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD -:10034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD -:10035000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD -:10036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D -:10037000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D -:10038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D -:10039000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D -:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D -:1003B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D -:1003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D -:1003D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D -:1003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D -:1003F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D -:10040000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC -:10041000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC -:10042000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC -:10043000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC -:10044000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC -:10045000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC -:10046000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C -:10047000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C -:10048000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C -:10049000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C -:1004A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C -:1004B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C -:1004C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C -:1004D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C -:1004E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C -:1004F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C -:10050000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB -:10051000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB -:10052000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB -:10053000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB -:10054000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB -:10055000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB -:10056000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B -:10057000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B -:10058000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B -:10059000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B -:1005A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B -:1005B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B -:1005C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B -:1005D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B -:1005E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B -:1005F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B -:10060000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA -:10061000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA -:10062000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA -:10063000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA -:10064000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA -:10065000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA -:10066000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A -:10067000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A -:10068000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A -:10069000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A -:1006A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A -:1006B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A -:1006C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A -:1006D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A -:1006E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A -:1006F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A -:10070000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 -:10071000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 -:10072000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 -:10073000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 -:10074000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 -:10075000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 -:10076000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 -:10077000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 -:10078000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 -:10079000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 -:1007A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 -:1007B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 -:1007C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 -:1007D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 -:1007E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 -:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 -:10080000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 -:10081000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 -:10082000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 -:10083000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 -:10084000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 -:10085000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 -:10086000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 -:10087000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 -:10088000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 -:10089000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 -:1008A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 -:1008B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 -:1008C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 -:1008D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 -:1008E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 -:1008F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 -:10090000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 -:10091000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 -:10092000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 -:10093000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 -:10094000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 -:10095000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 -:10096000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 -:10097000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 -:10098000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 -:10099000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 -:1009A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 -:1009B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 -:1009C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 -:1009D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 -:1009E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 -:1009F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 -:100A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 -:100A1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 -:100A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 -:100A3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 -:100A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 -:100A5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 -:100A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 -:100A7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 -:100A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 -:100A9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 -:100AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 -:100AB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 -:100AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 -:100AD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 -:100AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 -:100AF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 -:100B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 -:100B1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 -:100B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 -:100B3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 -:100B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 -:100B5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 -:100B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 -:100B7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 -:100B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 -:100B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 -:100BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 -:100BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 -:100BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 -:100BD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 -:100BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 -:100BF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 -:100C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 -:100C1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 -:100C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 -:100C3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 -:100C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 -:100C5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 -:100C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 -:100C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 -:100C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 -:100C9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 -:100CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 -:100CB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 -:100CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 -:100CD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 -:100CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 -:100CF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 -:100D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 -:100D1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 -:100D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 -:100D3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 -:100D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 -:100D5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 -:100D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 -:100D7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 -:100D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 -:100D9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 -:100DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 -:100DB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 -:100DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 -:100DD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 -:100DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 -:100DF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 -:100E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 -:100E1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 -:100E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 -:100E3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 -:100E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 -:100E5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 -:100E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 -:100E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 -:100E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 -:100E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 -:100EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 -:100EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 -:100EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 -:100ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 -:100EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 -:100EF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 -:100F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 -:100F1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 -:100F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 -:100F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 -:100F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 -:100F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 -:100F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 -:100F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 -:100F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 -:100F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 -:100FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 -:100FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 -:100FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 -:100FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 -:100FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 -:100FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 -:10100000D10020402C100060000000000000000013 -:1010100020100060001000600000000000000000D0 -:1010200000000060D031000000000000000001203E -:1010300035100060764B0720764C4FF42A01764A33 -:101040005C64186499639546744A75498A420FD066 -:10105000744B9A420CD2D4430846234423F0030332 -:1010600004330B4450F8041B984242F8041BF9D196 -:101070006D4A6E498A420FD06D4B9A420CD2D443CE -:101080000846234423F0030304330B4450F8041BA5 -:10109000984242F8041BF9D1664A674B9A420BD238 -:1010A000D04311460024034423F0030304331344C4 -:1010B00041F8044B8B42FBD1604A4FF47001604B06 -:1010C000116003F530715F4A43F8042F9942FBD158 -:1010D0005D4B80215D4A03F8011B9342FBD15C4CC0 -:1010E0004FF080375B4E4FF0FF32DFF8A8A10025AC -:1010F000DFF8A491DFF8A481574B4549C3F800A05D -:10110000C4F80471C4F80091C4F8F470C4F8F08015 -:10111000F36923F07F0343F04003F361736A23F024 -:101120007F0343F0400373628A66CA660A674A67B0 -:1011300000F0B6F8494A6320494B4A49106003223F -:101140001D60CAF8381043F8082C4749474A4848F8 -:10115000C3F8082D0B68474A43F08073CAF83C0077 -:1011600045480B601368454943F001031360036869 -:101170000B6000F0E5F8C4F804714148C4F8009130 -:10118000C4F8F470C4F8F08000F04AFA00BF00BF61 -:1011900000BF00BFF16E3B4A41F440513A4BF1664B -:1011A0001560C2F80851C2F81851C2F82851C2F8A7 -:1011B00038519A6BD20708D442F615623349596503 -:1011C0001A659A6B42F001029A632F4A304C936879 -:1011D00043F00113936000F01BFA2368132BFCD932 -:1011E00000F05CF900F0D0F900F00EFA00F0DAF847 -:1011F00000F002FA2368B3F5967FFBD300F018FAEB -:1012000000F0FEF900F01CFA00F016FAFAE700BF51 -:1012100000C00A40ABAAAAAA008007200000000074 -:1012200050160060C017000000000020142E00605F -:10123000C0030020C0030020C032002088ED00E081 -:10124000FC0F00208905000000E400E0A0E400E0BD -:1012500000800D4000C00F4008ED00E014E000E009 -:1012600018E000E001110000FCED00E0000020208B -:1012700005120000001000E0041000E0840D0020C2 -:101280000046C3230040084000400D400000C05607 -:10129000880D0020001000201B1018200C0D1113C9 -:1012A000F0B5194A0021194B4FF0100E18480124CF -:1012B000184E194D0160194FC2F800E01E6015600C -:1012C000174E184D1F601660174F1D60174E184DB2 -:1012D00017601E60174F1560174E184D1F6016607F -:1012E0001D600460BFF34F8FBFF36F8FC3F8B01161 -:1012F000BFF34F8FBFF36F8F52F8883C43F44033F6 -:1013000042F8883CF0BD00BF9CED00E0A0ED00E09D -:1013100094ED00E0250008031100200021000207E1 -:1013200012000020250008131300202027000B13B3 -:101330001400004033001013150000602F000B074D -:10134000F0B4174A40274FF480314FF480564FF4E1 -:1013500000554FF4404443F24200136913F0020F6A -:1013600006D0946151619061136913F0020FF8D1B6 -:1013700013F4005F01D15561EFE713F4805F01D1F1 -:101380005661EAE7002BE8DA13F4803F01D091615F -:10139000E3E75B0601D45761DFE7F0BC704700BFAD -:1013A00000800D40364A03203649F3EE096A13687F -:1013B00023F00103F0B51360C2F89000D1F8E030DB -:1013C000DFF8D4E0DCB2C3F30B202F4FC0EB135394 -:1013D00007EE904AA4F15501CEF80040B8EEE77A46 -:1013E00003EB830407EE900A03FB01F13B6003EB80 -:1013F0008313B8EEE75A07EE901A091B77EE666A78 -:10140000B8EE677A214D07EE901A0B44C5ED006ADD -:10141000F8EE677A1E4EC7EE265A1E4930601068F5 -:1014200087EEA66A07EE903AF8EE677A87EEA67A1C -:1014300075EE855A76EE056AFCEEE55AFCEEE66A34 -:1014400015EE903A40EA035316EE900A77EE057ACD -:10145000136001EA0041D2F81031FCEEE77A0B4349 -:10146000C2F8103117EE903AD2F81011C3F30B0303 -:101470000B43C2F81031136843F002031360F0BD50 -:1014800080810D4000441F40E8030020E403002059 -:10149000EC0300200000FF0FE0030020304B40F67B -:1014A000617270B5C3F8202140F2044500F0B4F831 -:1014B0002C492D48D1F880202C4C42F003022C4BB3 -:1014C000C1F88020C0F86051226813401BB9D0F8E1 -:1014D000A8319A071AD0244B4FF00041234A516398 -:1014E0001A46D3F8401141F00201C3F84011D2F876 -:1014F00040319B07FBD44FF400301E491B4B4FF08B -:101500000042086019209A6300F08EF81A4D0022FC -:10151000164B4FF08041144C0A26996328461A60F6 -:101520001146C4F8A8614FF4207200F061F84FF43E -:1015300081064FF4800040F24313104A10492E6098 -:101540002864C4F85851C2F80412C4F848310D4A4E -:101550004FF4003101231160C4F8403170BD00BF69 -:1015600000800D4000C00F4000002E4000900D4054 -:10157000001C1E008CE200E0003000200010002063 -:10158000650700000CE100E0114B1249D86E0A46D5 -:1015900040F4403030B4D86640F2B765D86EA0242D -:1015A00040F44070D8664D648C64936C1B06FCD488 -:1015B000094B40F2B760A021064A58649964936CC5 -:1015C00013F08003FBD1054A137030BC704700BF95 -:1015D00000C00F4000400C4000800C40810D0020F6 -:1015E000F8B500BFF8BC08BC9E467047FFFFFFFF80 -:1015F0005FF800F0111700005FF800F0A50500008B -:101600005FF800F0C90000005FF800F0D51300009B -:101610005FF800F0A10500005FF800F0650E000023 -:101620005FF800F0450200005FF800F0C51200000E -:101630005FF800F0C11600005FF800F0251200000E -:101640005FF800F0D100000045000000FFFFFFFF41 -:10165000000000000000000000000000000000008A -:10166000000000000000000000000000000000007A -:1016700010B5054C237833B9044B13B10448AFF3CC -:1016800000800123237010BDC00300200000000073 -:10169000C4170000084B10B51BB108490848AFF348 -:1016A00000800848036803B910BD074B002BFBD02E -:1016B000BDE81040184700BF00000000C403002030 -:1016C000C4170000C00300200000000008B50D4B47 -:1016D0000121187800F040FA0B4B0121187800F036 -:1016E0003BFA0A4B0121187800F036FA084B012129 -:1016F000187800F031FA074B01211878BDE808404E -:1017000000F02ABAEC020020F0020020F4020020CF -:10171000F8020020FC020020FFF7D8BF0000000004 -:101720002DE9F04F504D83B09FED507A0121D5ED5A -:10173000007ADFF850B167EE877ADFF84CA19BF8AA -:101740000000DFF84891FDEEE77ADFF84481484F6A -:10175000484E17EE904A00F0F9F99AF8000001217E -:1017600000F0F4F999F80000012104F57A7400F012 -:10177000EDF998F80000012100F0E8F9387801212E -:1017800000F0E4F93C483D49D0F800E03368A1FBA3 -:101790000331890C04FB01F10368374ACEEB0303E4 -:1017A0009942F9D89BF800000021019200F0CEF98F -:1017B0009AF80000002100F0C9F999F80000002112 -:1017C00000F0C4F998F80000002100F0BFF9387863 -:1017D000002100F0BBF9019A284942F21070176805 -:1017E0003368001BA1FB03139B0C03FB00F0136881 -:1017F0002149DB1B9842FAD8086842F2107332681C -:101800001E4CA4FB0242920C03FB02F20B681B1A53 -:101810009A42FBD81A4BF7EE006A95ED007A93EDE9 -:10182000005AB7EEC77AB7EEC55A9FED0D4BA5EE3D -:10183000047BB7EEC77BB4EEE67A85ED007AF1EE75 -:1018400010FA0ADDF0EE667A37EE677AB4EEE77AE0 -:10185000F1EE10FAF8DC85ED007A03B0BDE8F08F08 -:101860007B14AE47E17A943FDC03002000007A4409 -:10187000FC02002008030020041000E083DE1B436C -:1018800000030020EC020020F0020020F4020020FF -:10189000F80200208C4A8D4B90422DE9F0438C4D8C -:1018A0005C699969EF681DD98A4B984240F20181C1 -:1018B000894B40F22766DFF860E20344874D1A0A3D -:1018C000AEFB0232D30903EB830303EB830202F284 -:1018D000E243B34228BF3346A3F54873A5FB033662 -:1018E000F60804E07E4EB04294BF06260E26774AE4 -:1018F00007F01F0ED2F88030B64543F0C003C2F89F -:1019000080300AD2724B27F01F071A463743DF6038 -:101910001368002BFCDA07F01F0E14F000732ED1B1 -:10192000704D714AD5F810C015460CEA0202AA4261 -:101930000ABF4FF0C0534FF48052002284EA0305DF -:1019400015F0605F06D024F0605403F060535F4DE3 -:101950001C436C6181EA020313F4405F08D05B4BC7 -:1019600021F4405111431A469961936C1D07FCD430 -:1019700044F00074554A5461936C9906FCD40121DB -:101980005A4D0A4601FB02F300FB03F3AB4209D8B0 -:10199000072A00F28480013201FB02F300FB03F30B -:1019A000AB42F5D95248534D1844A5FB0030030D06 -:1019B0006C2B79D8352B7ED8DFF8608136234E48E2 -:1019C000DFF820C14D4DDCF80090B0FBF2F009EAE1 -:1019D00005054545B0FBF1F00BD043F400534FF43F -:1019E00080586546CCF80080CCF800302B68002B7E -:1019F000FCDADFF8D8C0013ADCF8103003F0070356 -:101A0000934207D002F007026546CCF81020AB6C79 -:101A1000DB03FCD40139890284EA010313F4E05F9B -:101A20000AD02A4B24F4E05401F4E0511A460C4346 -:101A30005C61936C9907FCD4314B32490344DB0958 -:101A4000A1FB0331090B042928BF04214B1E1B02F3 -:101A500084EA030212F4407F06D024F4407403F4B5 -:101A600040731A4A1C435461184B24F000741A4600 -:101A70005C61936C9B06FCD4B0FBF1F1224A764585 -:101A8000224B1060196008D2114B27F01F071A462D -:101A90003743DF601368002BFCDABDE8F0830429CC -:101AA00080D8013101226DE7DFF874806C2318487B -:101AB00086E712261BE71748DFF8688000FB03F073 -:101AC00043EA08087CE700BF00A4781F00C00F406D -:101AD000000008400046C32300BA3CDC1F85EB51E0 -:101AE00000366E0100800D4040300080FFB19F261F -:101AF000808D5B00819F5E1600B29F267F30018043 -:101B00007FD1F0089F10E5000803002004030020A7 -:101B100000643F4D001BB70023B24C00362000800C -:101B20006C200080002000800001074B1A181B5811 -:101B3000D2685868104202D011B9C3F888207047A3 -:101B4000C3F88420704700BF00000020272801D878 -:101B5000FFF7EABF704700BF27281CD800011A4AC8 -:101B6000012902EB0003105810B415D0042913D03A -:101B7000DC68426822EA040242609A68E9B10229FC -:101B80001ED003295B685DF8044B0CBF0F49104958 -:101B9000116015221A607047DA680129446842EA28 -:101BA000040242609A6808D040F6380111605B6810 -:101BB00015225DF8044B1A60704738211160F6E772 -:101BC00004491160F3E700BF000000203830010035 -:101BD0003800010038F0010004207146084203D0AB -:101BE000EFF3098000F008B8EFF3088000F004B8C4 -:101BF000704700BF704700BF1B4B05211B4A3820B0 -:101C000030B5C2F848110821C2F8380383B05A68C9 -:101C1000174C0A4317485A60C3F88410C3F8881059 -:101C20002368834202D91448FFF734FE0E4D08247E -:101C30000020124A1249C5F884400190019B93424A -:101C400005D8019B01330193019B9342F9D9C5F853 -:101C500088400190019B8B42EDD8019B0133019399 -:101C6000019B8B42F9D9E6E700C01B4000801F4072 -:101C700008030020FF45C32300A3E1113F420F00EA -:101C80003F548900836B30B41BB1536843F4004365 -:101C9000536072B6446B9CB1104B2260D3F8B041D4 -:101CA0000C4217D1D3F8404144F48044C3F840417A -:101CB000D3F8B851D3F840416404F3D5294209D18F -:101CC0000023064C8260C360D4F8B0311943C4F8D5 -:101CD000B0110263426362B630BC704700002E4010 -:101CE00038B50546036B06E0AA6B1C6890476A6B23 -:101CF0002346944208D0184633B1012B04D05A68C9 -:101D00001206F1D52B6338BD00232B636B6338BDFE -:101D1000F0B5F1B9224C23490020234B0122802544 -:101D2000A1600A601A464D60E060D3F8BC4188604B -:101D300044F001141D4DC3F8BC41D3F8B01141F07B -:101D40000101C3F8B0112860D2F8B031002BFBD1EB -:101D5000F0BD0904164B144D0126114C41F08001D1 -:101D600000221E60596000F5805CE26400F5005EB0 -:101D7000A36400F54057D5F8B01100F580462A4617 -:101D8000986041F48031C3F80CC0C3F810E05F6183 -:101D90009E61C5F8B011D2F8B031002BFBD1BAE783 -:101DA000003000202020002000002E40FC030020F6 -:101DB000002000202DE9F04FBB4C83B0D4F84481C3 -:101DC00018F0010FC4F844815ED0D4F8AC31002B78 -:101DD00055D04FF00119DFF8F0B22646B34FCA468E -:101DE000B96AFA6AC4F8AC31D4F8403143F400530C -:101DF000C4F84031D4F840319D04F5D5D6F84031CF -:101E000023F40053C6F84031C6F8B4A1D4F8B43175 -:101E100013F00113FAD188B240F28165CBF800309B -:101E2000A84200F29680B0F5D06F80F0D881B0F56E -:101E3000817F00F0578100F2D580802800F0268154 -:101E4000822840F0C78092B202F07F01072900F299 -:101E5000C18089009648974D0844016810062B7090 -:101E60006B7040F1E581C90301D501232B7002217C -:101E70009048FFF74DFFD4F8AC31002BB0D18A4A1F -:101E8000D2F8BC31002B44D118F0400F18D0864B4B -:101E9000D3F8AC111A46C3F8AC11D3F8BC11C3F88F -:101EA000BC11D2F8B041804B002CFAD14FF0FF3278 -:101EB000C3F8B421D3F8843100F074FB7E4B1C606E -:101EC00018F0807F03D07D4B1B6803B1984718F052 -:101ED000007F03D07A4B1B6803B1984718F0040FBA -:101EE00002D0714BD3F884316F4BD3F848211206DE -:101EF0000CD518F0800F09D072490A78002A00F03A -:101F00008E81531EDBB20B7003B9FBBE03B0BDE87C -:101F1000F08F6D49C2F8BC310868034240F0CC81B3 -:101F2000654A14681C40AFD0630700F1E281670383 -:101F300000F1EF81260700F1E881250300F1E1813E -:101F4000E00600F1DA81E1029ED56048FFF7C8FEA5 -:101F50009AE742F22105A84238D06FD8B0F5086F51 -:101F600000F02F81B0F5106F34D1C1F30741584A0A -:101F7000584811705849594A0193C6F8C801C6F823 -:101F8000CC11C6F8D02100F00FFB554A019B8021EF -:101F90000120FB6410605160D6F8BC11936041F0E1 -:101FA0000111BA64C6F8BC11D6F8B02142F48032EF -:101FB000C6F8B021444A1360D4F8B031002BFBD1ED -:101FC000D4F8AC31002B7FF40BAF58E7100C072886 -:101FD00000F03281C4F8C091D4F8AC31002B7FF40A -:101FE000FFAE4CE740F20235A84200F0B780B0F5F2 -:101FF000A06FEFD13A4A80200125FB645060156044 -:10200000D6F8BC01936040F00113BA64C6F8BC3145 -:10201000D6F8B03143F48033C6F8B031D4F8B031DB -:10202000002BFBD10B0C5B0643F08073C6F85431D8 -:10203000D4F8AC31002B7FF4D3AE20E742F2212359 -:10204000984200F0828042F221339842C2D1244B60 -:1020500001218022196000215A60D4F8BC21BB64A0 -:1020600042F001129960F964C4F8BC21D4F8B0318F -:1020700043F48033C4F8B031D4F8B031002BFBD135 -:10208000D4F8AC31002B7FF4ABAEF8E6094A02215C -:10209000104613705370FFF73BFED4F8AC31002BA1 -:1020A0007FF49EAEEBE600BF00002E400030002023 -:1020B000C0012E4010040020F4030020F003002093 -:1020C000F803002000040020FC0300204032002020 -:1020D000200400200200CC00C80002000200C8005A -:1020E0002020002092B202F07F03072B3FF672AF50 -:1020F00012F0800F4FEA8303884A4FF001011A441F -:10210000136814BF23F4803323F00103136080228B -:10211000834B196000215A60D4F8BC21BB6442F0A3 -:1021200001129960F964C4F8BC21D4F8B03143F4C9 -:102130008033C4F8B031D4F8B031002BFBD1D4F8DF -:10214000AC31002B7FF44CAE99E6764BC1F30741DE -:10215000754A1868754B1060197078E792B202F0F2 -:102160007F03072B3FF636AF12F0800F4FEA830351 -:102170006A4A4FF001011A44136814BF43F48033D4 -:1021800043F0010313608022654B196000215A60FF -:10219000D4F8BC21BB6442F001129960F964C4F820 -:1021A000BC21D4F8B03143F48033C4F8B031D4F852 -:1021B000B031002BFBD1D4F8AC31002B7FF410AE42 -:1021C0005DE65B4A01215B4B127818461A70FFF7F7 -:1021D0009FFDD4F8AC31002B7FF402AE4FE6564B96 -:1021E000586800283FF4F6AE090C1FFA82FE04E09E -:1021F0000C33586800283FF4EDAE1D888D42F7D1AE -:102200005D887545F4D1090A120C03290CBF0178C9 -:102210001989914228BF1146FFF77AFD2BE6D3F8C2 -:10222000482122F08002C3F8482103B0BDE8F08FB6 -:10223000CA077FF51CAE18E6404D0120FB602960FF -:102240003F4B4049186059603F49D6F8B0016A6079 -:1022500001F5005E40F00102A1F5005001F5805546 -:10226000BB609860A1F58050D860C6F8B0211961B4 -:102270005D61C3F818E0D4F8B031002BFBD1284AD7 -:10228000012048F28001FB6410604FF480305160FF -:10229000D6F8BC11936041F00113BA64C6F8BC31A2 -:1022A000D6F8B0310343C6F8B031CBF80000D4F80B -:1022B000B031002BFBD1DEE5204C42F2210000259D -:1022C00024880D6084427FF42BAE2049204C03C942 -:1022D0000D0C86282060A180A5717FF421AED2F874 -:1022E000481150241B4841F08001C2F84811047085 -:1022F00016E61948FFF7F4FC19E61848FFF7F0FC5A -:1023000021E61748FFF7ECFC1AE61648FFF7E8FC51 -:1023100013E61548FFF7E4FC0CE600BFC0012E40B1 -:1023200020200020880D002088320020600D002031 -:102330002004002010040020800200200804002057 -:10234000002000208000070018240020180400202E -:1023500080320020000400200031002000320020E4 -:10236000C03100208031002040310020002AA0F13F -:1023700002022DE9F04714BF00274FF00057022A50 -:1023800001D9BDE8F0874FEAC01ADFF840900D464A -:1023900004460AEB0906002140229846304600F028 -:1023A000DFFC012047EA05414AF80910C6F83880E9 -:1023B000B060B8F1000FE4D0034BA0401C6820438C -:1023C0001860BDE8F08700BFF40300200030002053 -:1023D000002AA0F102022DE9F04714BF00274FF0B8 -:1023E0000057022A01D9BDE8F0874022C501DFF875 -:1023F000449088461544002104461E4605EB090A10 -:10240000504600F0ADFC012247EA084145F80910AA -:10241000CAF83860CAF80820002EE4D004F1100091 -:10242000034B8240186802431A60BDE8F08700BF82 -:10243000F40300200030002012048160C36142F0E8 -:102440008002F0B44260012701F5805601F5005585 -:1024500001F5405401F580420760C66005614461A2 -:102460008261F0BC704700BF831E022B00D9704709 -:1024700030B4064B00F1100401250A4603EBC010EE -:1024800005FA04F130BCFFF7FDBB00BF403000206F -:10249000831E022B00D9704710B4054B01240A4655 -:1024A00004FA00F103EBC0105DF8044BFFF7EABB40 -:1024B00000300020124A134BD2F8200220F07F4057 -:1024C000984210B584B002D800EB800040000E4C5A -:1024D00001A90A2200F07EFA01A90023204611F882 -:1024E000012B01333AB10A2B20F8022FF7D1162322 -:1024F000237004B010BD5B00DBB2237004B010BDCC -:1025000000441F407F969800A40300204368C269DE -:10251000C3F30E43054930B4C3F14003044C002516 -:1025200021F8123024F8125030BC7047F00B002014 -:10253000E80B0020F8B5154B1B783BB903F0FF04FE -:10254000134B1B7813B1134D2A8802B9F8BD124FF3 -:102550002346124EC2F580723978114806EB4116B7 -:1025600000EB01213046FFF767FF31460420FFF7FB -:102570007BFF3B780133DBB2062B98BF3B704FF0FB -:10258000000388BF3C702B80F8BD00BF240B0020E7 -:1025900020040020600C0020250B0020800C00206F -:1025A00024040020704700BF0021E0222048F8B535 -:1025B0000C46204E204D00F0D3FB204F2146204BEF -:1025C0006022347028461F4E1C8000F0C9FB234651 -:1025D0002246102102203C60BC803460B480FFF7AA -:1025E000F7FE2246184B40210320FFF7BFFE23468B -:1025F000224640210420FFF7EBFE234640222846D6 -:102600001249FFF719FF29460320FFF741FF104B3E -:102610004A22104910480860C3F88440C3F880205B -:10262000D3F8482142F08072C3F84821F8BD00BFBA -:10263000800C0020250B0020000C0020F00B002057 -:10264000600C0020E80B0020BD0E0000280B0020CD -:1026500000002E40F0030020E50E0000024A034B6C -:1026600010881B88C01A7047F00B0020E80B002070 -:1026700010B4EFF3108272B6437F33B9017F0129A2 -:1026800008D0032910D00123437702B962B65DF860 -:10269000044B7047114C2168A1B1114943610B688B -:1026A000086083615861EEE70E4C216881B10E49E4 -:1026B00043610B680860836158610C4B4FF0805197 -:1026C0001960E0E7064B4161816120601860DAE73C -:1026D000054B4161816120601860EEE7740D0020B8 -:1026E000700D0020640D0020680D002004ED00E056 -:1026F00010B4047F4160022CC26003D05DF8044B2B -:10270000FFF7B6BF83685DF8044B184770B5EFF369 -:10271000108172B60C4C23688BB10C4E00255A699F -:1027200022607AB1956101B962B65D7718469B68FF -:102730009847EFF3108172B62368002BEFD101B9EF -:1027400062B670BD3260EEE7640D0020680D0020B7 -:10275000FFF7DCBF184A30B41468002C28D0036897 -:1027600021688B420FD2CB1A00218460C1602360A4 -:10277000E0601060022330BC0375704703601446AC -:1027800011688B4208D3A2685B1A002AF6D18260D6 -:10279000C4600360A060EDE7D568CB1A82600222B6 -:1027A000C560E060C16888602360027530BC704716 -:1027B0008460C4601060DDE76C0D0020F8B5224E27 -:1027C00034682CB32368002B3AD11D461F4F04E018 -:1027D0003468ECB12368002B32D1A36803B1DD600B -:1027E00020693360036825751B68BB4221D1037FD4 -:1027F0004560022BC46020D0FFF73AFF6368002BCE -:10280000E6D023602046FFF7A5FF3468002CE1D115 -:10281000EFF3108372B60E4A00211068116003B9FD -:1028200062B628B18468FFF795FF20460028F9D1E9 -:10283000F8BD224600219847E0E783689847DDE726 -:10284000013B2360E4E700BF6C0D0020A1100000F5 -:102850007C0D0020044A054B1168054A1960136875 -:1028600001331360FFF7AABF041000E0840D0020BD -:10287000880D002070B5214C237883B9204B0122AC -:102880001B7822701BBB1F4B1B78002B29D11E4BC2 -:1028900000211A68217012B1EFF3058202B170BDF8 -:1028A000EFF3108072B61A68F2B1184C2178D9B9DA -:1028B0000126556926701D60D5B1A96100B962B6BF -:1028C00000259368104655779847257070BDFFF72F -:1028D000C5FE0028D7D000F015FA0A4B1B78002B54 -:1028E000D5D000F0FBF9D2E70028D8D162B670BD90 -:1028F000074B1D600028E3D1E1E700BF800D0020F9 -:10290000BA030020A80D0020740D0020780D0020CF -:10291000700D0020002852D02DE9F04F814683B081 -:10292000274C0120274D284E54E8003F2A68316883 -:1029300044E80003002BF7D1244F4FF47A7E24485B -:10294000D7F800C0BB4607F1C6470368C1EB0C01CE -:1029500007F5DE1707F67F67A7FB03C3BA46012713 -:102960009B0CB1FBF3F30EFB023854E8003F2A68DE -:10297000316844E80073002BF7D1DBF800C04FF456 -:102980007A7E03680EFB02F2C1EB0C01AAFB033E48 -:10299000C8EB02034FEA9E42B1FBF2F1CA18B2F54E -:1029A0007A7F07D3B9F1010908F57A78DDD103B050 -:1029B000BDE8F08F0190FFF75DFF0198D5E7704704 -:1029C0008C320020880D0020840D0020041000E0CF -:1029D00008030020F0B44E1E0025374600E0013504 -:1029E000B0FBF2F302FB130000F13704092800F1F9 -:1029F0003000E4B298BFC4B2184607F8014F002B6C -:102A0000EDD14A1953704DB1013316F8014F1778C3 -:102A1000E81A3770834202F80149F5DB0846F0BC3A -:102A2000704700BFA4484FF00F0CA44B826F42F4D4 -:102A30007F02F0B582670025D0F880204FF4704601 -:102A40009F4C4FF4604E29464FF4806714432A464A -:102A5000C0F88040A3F88C6148F2B826A3F88EC174 -:102A6000A3F89051B3F8880180B240F0F000A3F8C9 -:102A7000880101EB4100914B0131002540011C46CA -:102A800004290344A3F804E0DF805A841A865A809C -:102A90005A81DE815A82DA825A83DA83E9D1B4F824 -:102AA00088014FF00F0C874B4FF4704680B22946D7 -:102AB0004FF460472A4640EA0C004FF4806EA4F8B9 -:102AC0008801B4F8880180B240F47060A4F88801ED -:102AD000A3F88C6148F2B826A3F88EC1A3F89051F0 -:102AE000B3F8880180B240F0F000A3F8880101EB50 -:102AF0004100744B0131002540011C460429034468 -:102B00009F80A3F806E05A841A865A805A81DE8193 -:102B10005A82DA825A83DA83E9D1B4F888014FF015 -:102B20000F0C694B4FF4704680B229464FF4604752 -:102B30002A4640EA0C004FF4806EA4F88801B4F8ED -:102B4000880180B240F47060A4F88801A3F88C6119 -:102B500048F2B826A3F88EC1A3F89051B3F88801C3 -:102B600080B240F0F000A3F8880101EB4100564B21 -:102B70000131002540011C46042903449F80A3F82D -:102B800006E05A841A865A805A81DE815A82DA8295 -:102B90005A83DA83E9D1B4F888014FF00F0C4B4B1C -:102BA0004FF4704780B229464FF460462A4640EA07 -:102BB0000C004FF4806EA4F88801B4F8880180B24C -:102BC00040F47060A4F88801A3F88C7148F2B8272B -:102BD000A3F88EC1A3F89051B3F8880180B240F0F9 -:102BE000F000A3F8880101EB4100384B01314001AE -:102BF0001C46042903449E80A3F806E05A841A86E2 -:102C00005A805A81DF815A82DA825A83DA83EAD182 -:102C1000B4F888310F27002241F201069BB245F635 -:102C2000C05E114643F226053B43A4F88831B4F850 -:102C300088319BB243F47063A4F888315001244B6F -:102C400001320344042A99815981DF819E82A3F8CD -:102C500006E0198019829D81F0D100220F2741F2F0 -:102C6000010645F6C055114643F226045001194BA2 -:102C700001320344042A99815981DF819E82DD80DB -:102C8000198019829C81F1D100220F2741F201069F -:102C900045F6C055114643F2260450010E4B013251 -:102CA0000344042A99815981DF819E82DD80198045 -:102CB00019829C81F1D1F0BD00C00F4000C03D40A1 -:102CC000000003FC00003E4000403E4000803E40CB -:102CD00000C01D4000001E4000401E4038B5074B9C -:102CE0001C784CB1064D55F8043F002BFBD098479B -:102CF000631E13F0FF04F6D138BD00BFA80D0020FD -:102D0000880D0020014B00221A707047BA03002082 -:102D100070B50F4E0F4D761BB61018BF002405D0AE -:102D2000013455F8043B9847A642F9D10A4E0B4DA1 -:102D3000761B00F065F8B61018BF002406D00134E9 -:102D400055F8043B9847A642F9D170BD70BD00BF4D -:102D500048160060481600604C1600604816006077 -:102D600070B4840746D0541E002A41D0CDB2034629 -:102D700002E0621EE4B3144603F8015B9A07F8D13F -:102D8000032C2ED9CDB245EA05250F2C45EA054581 -:102D900019D903F110022646103E0F2E42F8105C9E -:102DA00042F80C5C42F8085C42F8045C02F1100244 -:102DB000F2D8A4F1100222F00F0204F00F04103236 -:102DC000032C13440DD91E462246043A032A46F822 -:102DD000045BFAD8221F22F003020432134404F0E9 -:102DE00003042CB1C9B21C4403F8011BA342FBD15C -:102DF00070BC704714460346C2E700BF00000000E5 -:102E00005FF800F0E1150060000000000000000025 -:042E1000F8B500BF52 -:102E140000000042C8801F40B8821F400800000024 -:102E240000000042C4801F40B4821F400400000020 -:102E340000C0004224801F4014821F401000000084 -:102E440000C0004228801F4018821F40200000005C -:102E540000C000422C801F401C821F404000000024 -:102E640000C0004234801F4024821F400001000043 -:102E74000040004264811F4054831F40000400004E -:102E84000040004280811F4070831F400000020008 -:102E9400004000427C811F406C831F400000010001 -:102EA4000040004268811F4058831F400008000012 -:102EB400004000423C811F402C831F400100000061 -:102EC4000040004244811F4034831F40040000003E -:102ED4000040004240811F4030831F400200000038 -:102EE4000040004248811F4038831F400800000012 -:102EF4000000004204811F40F4821F4000000400CF -:102F04000000004208811F40F8821F4000000800B2 -:102F14000000004218811F4008831F400000800009 -:102F24000000004214811F4004831F400000400041 -:102F34000000004200811F40F0821F400000020098 -:102F440000000042FC801F40EC821F400000010092 -:102F54000000004224811F4014831F40000000042D -:102F64000000004228811F4018831F400000000811 -:102F7400000000421C811F400C831F400000000120 -:102F84000000004220811F4010831F400000000207 -:102F940000000042EC801F40DC821F400010000053 -:102FA40000000042F0801F40E0821F40002000002B -:102FB4000000004234811F4024831F400000004071 -:102FC4000000004238811F4028831F400000008019 -:102FD4000080004294801F4084821F40000004004F -:102FE40000C0004290801F4080821F40000000808B -:102FF40000800042A8801F4098821F40000080008B -:1030040000800042A4801F4094821F4000004000C2 -:10301400004000426C811F405C831F400010000090 -:1030240000C0004230801F4020821F40800000000A -:1030340000800042C8811F40B8831F400080000008 -:1030440000800042C4811F40B4831F400040000040 -:1030540000800042C0811F40B0831F400020000058 -:1030640000800042BC811F40AC831F400010000060 -:1030740000800042D0811F40C0831F400000020036 -:1030840000800042CC811F40BC831F40000001002F -:10309400000100007403002012000000000600007C -:1030A4000C0300200A00000000020000300300208E -:1030B400430000000007000030030020430000002C -:1030C40000030000A0030020000000000103090425 -:1030D40018030020000000000203090488030020F4 -:1030E4000000000003030904A40300200000000002 -:1030F4000000000000000000000000000D000000BF -:103104000E0000000F00000010000000110000007D -:103114000000803F0029DE07007B9A170A060002A0 -:10312400020000400100000018035400650065001F -:103134006E00730079006400750069006E006F0012 -:1031440009024300020100C0320904000001020226 -:1031540001000524001001052401010104240206D4 -:10316400052406000107058203100010090401006C -:10317400020A00000007050302400000070584025C -:10318400400000001201000202000040C016830447 -:1031940079020102030100001603550053004200A6 -:1031A4002000530065007200690061006C0000009B -:1031B400040309040C0300000000000000000000E8 -:1031C40000000000000000000000010000000000FA -:040000056000100087 -:00000001FF diff --git a/tools/odrive/tests/step_dir_test.py b/tools/odrive/tests/step_dir_test.py new file mode 100644 index 00000000..161ed2ec --- /dev/null +++ b/tools/odrive/tests/step_dir_test.py @@ -0,0 +1,92 @@ + +import test_runner + +import struct +import asyncio +import time + +from fibre.utils import Logger +from odrive.enums import * +from test_runner import * + +class TestStepDir(): + """ + Tests Step/Dir input. + Not all possible combinations are tested, but each axis and each GPIO + participates in at least one test case. + + The tests are conducted while the axis is in idle. + """ + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + gpio_conns = [ + list(testrig.get_connected_components((odrive.gpio1, False), LinuxGpioComponent)), + list(testrig.get_connected_components((odrive.gpio2, False), LinuxGpioComponent)), + list(testrig.get_connected_components((odrive.gpio3, False), LinuxGpioComponent)), + list(testrig.get_connected_components((odrive.gpio4, False), LinuxGpioComponent)), + list(testrig.get_connected_components((odrive.gpio5, False), LinuxGpioComponent)), + list(testrig.get_connected_components((odrive.gpio6, False), LinuxGpioComponent)), + list(testrig.get_connected_components((odrive.gpio7, False), LinuxGpioComponent)), + list(testrig.get_connected_components((odrive.gpio8, False), LinuxGpioComponent)), + ] + + yield (odrive.axes[0], 1, gpio_conns[0], 2, gpio_conns[1]) + yield (odrive.axes[0], 3, gpio_conns[2], 4, gpio_conns[3]) + yield (odrive.axes[0], 5, gpio_conns[4], 6, gpio_conns[5]) # broken + yield (odrive.axes[0], 7, gpio_conns[6], 8, gpio_conns[7]) # broken + + yield (odrive.axes[1], 7, gpio_conns[6], 8, gpio_conns[7]) + + def run_test(self, axis: ODriveAxisComponent, step_gpio_num: int, step_gpio: LinuxGpioComponent, dir_gpio_num: int, dir_gpio: LinuxGpioComponent, logger: Logger): + step_gpio.config(output=True) + step_gpio.write(False) + dir_gpio.config(output=True) + dir_gpio.write(True) + + if axis.num == 0: + axis.parent.handle.config.enable_uart = False + axis.handle.config.enable_step_dir = True + axis.handle.config.step_dir_always_on = True # needed for testing + axis.handle.config.step_gpio_pin = step_gpio_num + axis.handle.config.dir_gpio_pin = dir_gpio_num + request_state(axis, AXIS_STATE_IDLE) # apply step_dir_always_on config + + + ref = axis.handle.controller.input_pos + axis.handle.config.counts_per_step = counts_per_step = 10 + + # On the RPi 4 a ~5kHz GPIO signal can be generated from Python + + for i in range(100): + step_gpio.write(True) + step_gpio.write(False) + test_assert_eq(axis.handle.controller.input_pos, ref + (i + 1) * counts_per_step, range = 0.4 * counts_per_step) + + ref = axis.handle.controller.input_pos + dir_gpio.write(False) + + for i in range(100): + step_gpio.write(True) + step_gpio.write(False) + test_assert_eq(axis.handle.controller.input_pos, ref - (i + 1) * counts_per_step, range = 0.4 * counts_per_step) + + ref = axis.handle.controller.input_pos + dir_gpio.write(True) + axis.handle.config.counts_per_step = counts_per_step = 1 + + for i in range(100): + step_gpio.write(True) + step_gpio.write(False) + test_assert_eq(axis.handle.controller.input_pos, ref + (i + 1) * counts_per_step, range = 0.4 * counts_per_step) + + ref = axis.handle.controller.input_pos + axis.handle.config.counts_per_step = counts_per_step = -1 + + for i in range(100): + step_gpio.write(True) + step_gpio.write(False) + test_assert_eq(axis.handle.controller.input_pos, ref + (i + 1) * counts_per_step, range = 0.4 * abs(counts_per_step)) + + +if __name__ == '__main__': + test_runner.run(TestStepDir()) diff --git a/tools/odrive/tests/test_runner.py b/tools/odrive/tests/test_runner.py index cab97478..c3787641 100644 --- a/tools/odrive/tests/test_runner.py +++ b/tools/odrive/tests/test_runner.py @@ -6,12 +6,21 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) import stat import odrive +import fibre from fibre import Logger, Event import argparse import yaml from inspect import signature import itertools import time +import tempfile +import io +from typing import Union, Tuple + +# needed for curve fitting +import numpy as np +import scipy.optimize +import scipy.ndimage.filters # Assert utils ----------------------------------------------------------------# @@ -39,20 +48,131 @@ def test_assert_eq(observed, expected, range=None, accuracy=None): raise TestFailed("value mismatch: expected {} but observed {}".format(expected, observed)) +# Other utils -----------------------------------------------------------------# + +def disjoint_sets(list_of_sets: list): + while len(list_of_sets): + current_set, list_of_sets = list_of_sets[0], list_of_sets[1:] + did_update = True + while did_update: + did_update = False + for i, s in enumerate(list_of_sets): + if len(current_set.intersection(s)): + current_set = current_set.union(s) + list_of_sets = list_of_sets[:i] + list_of_sets[(i+1):] + did_update = True + yield current_set + +def is_list_like(arg): + return hasattr(arg, '__iter__') and not isinstance(arg, str) + +def all_unique(lst): + seen = list() + return not any(i in seen or seen.append(i) for i in lst) + +def modpm(val, range): + return ((val + (range / 2)) % range) - (range / 2) + +def fit_line(data): + func = lambda x, a, b: x*a + b + slope, offset = scipy.optimize.curve_fit(func, data[:,0], data[:,1], [1.0, 0])[0] + return slope, offset, func(data[:,0], slope, offset) + +def fit_sawtooth(data, min_val, max_val, sigma=10): + """ + Fits the data to a sawtooth function. + Returns the average absolute error and the number of outliers. + The sample data must span at least one full period. + data is expected to contain one row (t, y) for each sample. + """ + + # Sawtooth function with free parameters for period and x-shift + func = lambda x, a, b: np.mod(a * x + b, max_val - min_val) + min_val + + # Fit period and x-shift + mid_point = (min_val + max_val) / 2 + filtered_data = scipy.ndimage.filters.gaussian_filter(data[:,1], sigma=sigma) + if max_val > min_val: + zero_crossings = data[np.where((filtered_data[:-1] > mid_point) & (filtered_data[1:] < mid_point))[0], 0] + else: + zero_crossings = data[np.where((filtered_data[:-1] < mid_point) & (filtered_data[1:] > mid_point))[0], 0] + + + if len(zero_crossings) == 0: + # No zero-crossing - fit simple line + slope, offset, _ = fit_line(data) + + elif len(zero_crossings) == 1: + # One zero-crossing - fit line based on the longer half + z_index = np.where(data[:,0] > zero_crossings[0])[0][0] + if z_index > len(data[:,0]): + slope, offset, _ = fit_line(data[:z_index]) + else: + slope, offset, _ = fit_line(data[z_index:]) + + else: + # Two or more zero-crossings - determine period based on average distance between zero-crossings + + period = (zero_crossings[1:] - zero_crossings[:-1]).mean() + slope = (max_val - min_val) / period + + #shift = scipy.optimize.curve_fit(lambda x, b: func(x, period, b), data[:,0], data[:,1], [0.0])[0][0] + if np.std(np.mod(zero_crossings, period)) < np.std(np.mod(zero_crossings + period/2, period)): + shift = np.mean(np.mod(zero_crossings, period)) + else: + shift = np.mean(np.mod(zero_crossings + period/2, period)) - period/2 + offset = -slope * shift + + return slope, offset, func(data[:,0], slope, offset) + +def test_curve_fit(data, fitted_curve, max_mean_err, inlier_range, max_outliers): + def save(): + import json + filename = '/tmp/log.json' + print('saving data to ' + filename) + with open(filename, 'w+') as fp: + json.dump(np.concatenate([data, np.array([fitted_curve]).transpose()], 1).tolist(), fp, indent=2) + + diffs = data[:,1] - fitted_curve + + mean_err = np.abs(diffs).mean() + if mean_err > max_mean_err: + save() + raise TestFailed("curve fit has too large mean error: {} > {}".format(mean_err, max_mean_err)) + + outliers = np.count_nonzero((diffs > inlier_range) | (diffs < -inlier_range)) + if outliers > max_outliers: + save() + raise TestFailed("curve fit has too many outliers (err > {}): {} > {}".format(inlier_range, outliers, max_outliers)) + + # Test Components -------------------------------------------------------------# -class ODriveTestContext(): +class Component(object): + def __init__(self, parent): + self.parent = parent + +class ODriveComponent(Component): def __init__(self, yaml: dict): self.handle = None self.yaml = yaml - #self.axes = [AxisTestContext(None), AxisTestContext(None)] - self.encoders = [EncoderTestContext(self, 0, None), EncoderTestContext(self, 1, None)] - self.axes = [AxisTestContext(self, 0, None), AxisTestContext(self, 1, None)] + #self.axes = [ODriveAxisComponent(None), ODriveAxisComponent(None)] + self.encoders = [ODriveEncoderComponent(self, 0, yaml['encoder0']), ODriveEncoderComponent(self, 1, yaml['encoder1'])] + self.axes = [ODriveAxisComponent(self, 0, yaml['motor0']), ODriveAxisComponent(self, 1, yaml['motor1'])] + for i in range(1,9): + self.__setattr__('gpio' + str(i), Component(self)) + self.can = Component(self) - def __repr__(self): - return self.yaml['name'] + def get_subcomponents(self): + for enc_ctx in self.encoders: + yield 'encoder' + str(enc_ctx.num), enc_ctx + for axis_ctx in self.axes: + yield 'axis' + str(axis_ctx.num), axis_ctx + for i in range(1,9): + yield ('gpio' + str(i)), getattr(self, 'gpio' + str(i)) + yield 'can', self.can - def make_available(self, logger: Logger): + def prepare(self, logger: Logger): """ Connects to the ODrive """ @@ -61,7 +181,8 @@ class ODriveTestContext(): logger.debug('waiting for {} ({})'.format(self.yaml['name'], self.yaml['serial-number'])) self.handle = odrive.find_any( - path="usb", serial_number=self.yaml['serial-number'], timeout=30)#, printer=print) + path="usb", serial_number=self.yaml['serial-number'], timeout=60)#, printer=print) + assert(self.handle) #for axis_idx, axis_ctx in enumerate(self.axes): # axis_ctx.handle = self.handle.__dict__['axis{}'.format(axis_idx)] for encoder_idx, encoder_ctx in enumerate(self.encoders): @@ -70,58 +191,361 @@ class ODriveTestContext(): for axis_idx, axis_ctx in enumerate(self.axes): axis_ctx.handle = self.handle.__dict__['axis{}'.format(axis_idx)] -class MotorTestContext(): + def unuse_gpios(self): + self.handle.config.enable_uart = False + self.handle.axis0.config.enable_step_dir = False + self.handle.axis1.config.enable_step_dir = False + self.handle.config.gpio1_pwm_mapping.endpoint = None + self.handle.config.gpio2_pwm_mapping.endpoint = None + self.handle.config.gpio3_pwm_mapping.endpoint = None + self.handle.config.gpio4_pwm_mapping.endpoint = None + self.handle.config.gpio3_analog_mapping.endpoint = None + self.handle.config.gpio4_analog_mapping.endpoint = None + + def save_config_and_reboot(self): + self.handle.save_configuration() + try: + self.handle.reboot() + except fibre.ChannelBrokenException: + pass # this is expected + self.handle = None + time.sleep(2) + self.prepare(logger) + +class MotorComponent(Component): def __init__(self, yaml: dict): self.yaml = yaml - - def __repr__(self): - return self.yaml['name'] - def make_available(self, logger: Logger): + def prepare(self, logger: Logger): pass -class AxisTestContext(): - def __init__(self, odrv_ctx: ODriveTestContext, num: int, yaml: dict): +class ODriveAxisComponent(Component): + def __init__(self, parent: ODriveComponent, num: int, yaml: dict): + Component.__init__(self, parent) self.handle = None - self.yaml = odrv_ctx.yaml[f'motor{num}'] # TODO: this is bad naming - self.odrv_ctx = odrv_ctx + self.yaml = yaml # TODO: this is bad naming self.num = num - - def __repr__(self): - return str(self.odrv_ctx) + '.axis' + str(self.num) - def make_available(self, logger: Logger): - self.odrv_ctx.make_available(logger) + def prepare(self, logger: Logger): + self.parent.prepare(logger) -class EncoderTestContext(): - def __init__(self, odrv_ctx: ODriveTestContext, num: int, yaml: dict): +class ODriveEncoderComponent(Component): + def __init__(self, parent: ODriveComponent, num: int, yaml: dict): + Component.__init__(self, parent) self.handle = None - self.odrv_ctx = odrv_ctx + self.yaml = yaml self.num = num - - def __repr__(self): - return str(self.odrv_ctx) + '.encoder' + str(self.num) + self.z = Component(self) + self.a = Component(self) + self.b = Component(self) - def make_available(self, logger: Logger): - self.odrv_ctx.make_available(logger) + def get_subcomponents(self): + return [('z', self.z), ('a', self.a), ('b', self.b)] -class CANTestContext(): + def prepare(self, logger: Logger): + self.parent.prepare(logger) + +class EncoderComponent(Component): + def __init__(self, parent: Component, yaml: dict): + Component.__init__(self, parent) + self.yaml = yaml + self.z = Component(self) + self.a = Component(self) + self.b = Component(self) + + def get_subcomponents(self): + return [('z', self.z), ('a', self.a), ('b', self.b)] + +class GeneralPurposeComponent(Component): def __init__(self, yaml: dict): + self.components = {} + for component_yaml in yaml.get('components', []): + if component_yaml['type'] == 'can': + self.components[component_yaml['name']] = CanInterfaceComponent(self, component_yaml) + if component_yaml['type'] == 'uart': + self.components[component_yaml['name']] = SerialPortComponent(self, component_yaml) + if component_yaml['type'] == 'gpio': + self.components['gpio' + str(component_yaml['num'])] = LinuxGpioComponent(self, component_yaml) + + def get_subcomponents(self): + return self.components.items() + +class LinuxGpioComponent(Component): + def __init__(self, parent: Component, yaml: dict): + Component.__init__(self, parent) + self.num = int(yaml['num']) + + def config(self, output: bool): + with open("/sys/class/gpio/gpio{}/direction".format(self.num), "w") as fp: + fp.write('out' if output else '0') + + def write(self, state: bool): + with open("/sys/class/gpio/gpio{}/value".format(self.num), "w") as fp: + fp.write('1' if state else '0') + + +class SerialPortComponent(Component): + def __init__(self, parent: Component, yaml: dict): + Component.__init__(self, parent) + self.yaml = yaml + + def get_subcomponents(self): + yield 'tx', Component(self) + yield 'rx', Component(self) + + def open(self, baudrate: int): + import serial + return serial.Serial(self.yaml['port'], baudrate, timeout=1) + +class CanInterfaceComponent(Component): + def __init__(self, parent: Component, yaml: dict): + Component.__init__(self, parent) self.handle = None self.yaml = yaml - def make_available(self, logger: Logger): + def prepare(self, logger: Logger): if not self.handle is None: return - # TODO: read bus name from yaml import can - self.handle = can.interface.Bus(bustype='socketcan', channel=self.yaml['id'], bitrate=250000) + self.handle = can.interface.Bus(bustype='socketcan', channel=self.yaml['interface'], bitrate=250000) + +class TeensyGpio(Component): + def __init__(self, parent: Component, num: int): + Component.__init__(self, parent) + self.num = num + +class TeensyComponent(Component): + def __init__(self, testrig, yaml: dict): + self.testrig = testrig + self.yaml = yaml + self.gpios = [TeensyGpio(self, i) for i in range(24)] + self.routes = [] + self.previous_routes = object() + + def get_subcomponents(self): + for i, gpio in enumerate(self.gpios): + yield ('gpio' + str(i)), gpio + yield 'program', Component(self) + + def add_route(self, input: TeensyGpio, output: TeensyGpio, noise_enable: TeensyGpio): + self.routes.append((input, output, noise_enable)) + + def commit_routing_config(self, logger: Logger): + if self.previous_routes == self.routes: + self.routes = [] + return + + code = '' + code += 'bool noise = false;\n' + code += 'void setup() {\n' + for i, o, n in self.routes: + code += ' pinMode({}, OUTPUT);\n'.format(o.num) + code += '}\n' + code += 'void loop() {\n' + code += ' noise = !noise;\n' + for i, o, n in self.routes: + if n: + # with noise enable + code += ' digitalWrite({}, digitalRead({}) ? noise : digitalRead({}));\n'.format(o.num, n.num, i.num) + else: + # no noise enable + code += ' digitalWrite({}, digitalRead({}));\n'.format(o.num, i.num) + code += '}\n' + + self.compile_and_program(code) + + self.previous_routes = self.routes + self.routes = [] + + def compile(self, sketchfile, hexfile): + env = os.environ.copy() + env['ARDUINO_COMPILE_DESTINATION'] = hexfile + run_shell( + ['arduino', '--board', 'teensy:avr:teensy40', '--verify', sketchfile], + logger, env = env, timeout = 60) + + def program(self, hex_file_path: str, logger: Logger): + """ + Programs the specified hex file onto the Teensy. + To reset the Teensy, a GPIO of the local system must be connected to the + Teensy's "Program" pin. + """ + + # todo: this should be treated like a regular setup resource + program_gpio = self.testrig.get_directly_connected_components(self.testrig.get_component_name(self) + '.program')[0] + + # Put Teensy into program mode by pulling it's program pin down + program_gpio.config(output = True) + program_gpio.write(False) + time.sleep(0.1) + program_gpio.write(True) + + run_shell(["teensy-loader-cli", "-mmcu=imxrt1062", "-w", hex_file_path], logger, timeout = 5) + time.sleep(0.5) # give it some time to boot + + def compile_and_program(self, code: str): + with tempfile.TemporaryDirectory() as temp_dir: + with open(os.path.join(temp_dir, 'code.ino'), 'w+') as code_fp: + code_fp.write(code) + code_fp.flush() + code_fp.seek(0) + print('Writing code to teensy: ') + print(code_fp.read()) + with tempfile.NamedTemporaryFile(suffix='.hex') as hex_fp: + self.compile(code_fp.name, hex_fp.name) + self.program(hex_fp.name, logger) + +class LowPassFilterComponent(Component): + def __init__(self, parent: Component): + Component.__init__(self, parent) + self.en = Component(self) + + def get_subcomponents(self): + yield 'en', self.en + + +class ProxiedComponent(Component): + def __init__(self, impl, *gpio_tuples): + """ + Each element in gpio_tuples should be a tuple of the form: + (teensy: TeensyComponent, gpio_in, gpio_out, gpio_noise_enable) + """ + Component.__init__(self, getattr(impl, 'parent', None)) + self.impl = impl + assert(all([len(t) == 4 for t in gpio_tuples])) + self.gpio_tuples = list(gpio_tuples) + + def __repr__(self): + return testrig.get_component_name(self.impl) + ' (routed via ' + ', '.join((testrig.get_component_name(t) + ': ' + str(i.num) + ' => ' + str(o.num)) for t, i, o, n in self.gpio_tuples) + ')' + + def __eq__(self, obj): + return isinstance(obj, ProxiedComponent) and (self.impl == obj.impl) # and (self.gpio_tuples == obj.gpio_tuples) + + def prepare(self): + for teensy, gpio_in, gpio_out, gpio_noise_enable in self.gpio_tuples: + teensy.add_route(gpio_in, gpio_out, gpio_noise_enable) + +class TestRig(): + def __init__(self, yaml: dict, logger: Logger): + # Contains all components (including subcomponents). + # Ports are components too. + self.components_by_name = {} # {'name': object, ...} + self.names_by_component = {} # {'name': object, ...} + + def add_component(name, component): + self.components_by_name[name] = component + self.names_by_component[component] = name + if hasattr(component, 'get_subcomponents'): + for subname, subcomponent in component.get_subcomponents(): + add_component(name + '.' + subname, subcomponent) + + for component_yaml in yaml['components']: + if component_yaml['type'] == 'odrive': + add_component(component_yaml['name'], ODriveComponent(component_yaml)) + elif component_yaml['type'] == 'generalpurpose': + add_component(component_yaml['name'], GeneralPurposeComponent(component_yaml)) + elif component_yaml['type'] == 'teensy': + add_component(component_yaml['name'], TeensyComponent(self, component_yaml)) + elif component_yaml['type'] == 'motor': + add_component(component_yaml['name'], MotorComponent(component_yaml)) + elif component_yaml['type'] == 'encoder': + add_component(component_yaml['name'], EncoderComponent(self, component_yaml)) + elif component_yaml['type'] == 'lpf': + add_component(component_yaml['name'], LowPassFilterComponent(self)) + else: + logger.warn('test rig has unsupported component ' + component_yaml['type']) + continue + + # List of disjunct sets, where each set holds references of the mutually connected components + self.connections = [] + for connection_yaml in yaml['connections']: + self.connections.append(set(self.components_by_name[name] for name in connection_yaml)) + self.connections = list(disjoint_sets(self.connections)) + + # Dict for fast lookup of the connection sets for each port + self.net_by_component = {} + for s in self.connections: + for port in s: + self.net_by_component[port] = s + + def get_components(self, t: type): + """Returns a tuple (name, component) for all components that are of the specified type""" + return (comp for comp in self.names_by_component.keys() if isinstance(comp, t)) + + def get_component_name(self, component: Component): + if isinstance(component, ProxiedComponent): + return self.names_by_component[component.impl] + else: + return self.names_by_component[component] + + def get_directly_connected_components(self, component: Union[str, Component]): + """ + Returns all components that are directly connected to the specified + component, excluding the specified component itself. + """ + if isinstance(component, str): + component = self.components_by_name[component] + result = self.net_by_component.get(component, set([component])) + return [c for c in result if (c != component)] + + def get_connected_components(self, src: Union[dict, Tuple[Union[Component, str], bool]], comp_type: type = None): + """ + Returns all components that are either directly or indirectly (through a + Teensy) connected to the specified component(s). + + component: Either: + - A component object. + - A component name given as string. + - A tuple of the form (comp, dir) where comp is a component object + or name and dir specifies the data direction. + The direction is required if routing through a Teensy should be + considered. + - A dict {sumcomponent: val} where subcomponent is a string + such as 'tx' or 'rx' and val is of one of the forms described above. + + A type can be specified to filter the connected components. + """ + + if isinstance(src, dict): + component_list = [] + for name, subsrc in src.items(): + component_list.append([c for c in self.get_connected_components(subsrc) if self.get_component_name(c).endswith('.' + name)]) + + for combination in itertools.product(*component_list): + if len(set(c.parent for c in combination)) != 1: + continue # parent of the components don't match + proxied_dst = combination[0].parent + if comp_type and not isinstance(proxied_dst, comp_type): + continue # not the requested type + gpio_tuples = [c2 for c in combination for c2 in c.gpio_tuples if isinstance(c, ProxiedComponent)] + if len(gpio_tuples): + yield ProxiedComponent(proxied_dst, *gpio_tuples) + else: + yield proxied_dst + + else: + + if isinstance(src, tuple): + src, dir = src + else: + dir = None + + for dst in self.get_directly_connected_components(src): + if (not comp_type) or isinstance(dst, comp_type): + yield dst + + if (not dir is None) and isinstance(getattr(dst, 'parent', None), TeensyComponent): + teensy = dst.parent + for gpio2 in teensy.gpios: + for proxied_dst in self.get_directly_connected_components(gpio2): + if (not comp_type) or isinstance(proxied_dst, comp_type): + yield ProxiedComponent(proxied_dst, (teensy, dst if dir else gpio2, gpio2 if dir else dst, None)) # Helper functions ------------------------------------------------------------# -def request_state(axis_ctx: AxisTestContext, state, expect_success=True): +def request_state(axis_ctx: ODriveAxisComponent, state, expect_success=True): axis_ctx.handle.requested_state = state time.sleep(0.001) if expect_success: @@ -131,7 +555,7 @@ def request_state(axis_ctx: AxisTestContext, state, expect_success=True): test_assert_eq(axis_ctx.handle.error, AXIS_ERROR_INVALID_STATE) axis_ctx.handle.error = AXIS_ERROR_NONE # reset error -def get_errors(axis_ctx: AxisTestContext): +def get_errors(axis_ctx: ODriveAxisComponent): errors = [] if axis_ctx.handle.motor.error != 0: errors.append("motor failed with error 0x{:04X}".format(axis_ctx.handle.motor.error)) @@ -145,41 +569,12 @@ def get_errors(axis_ctx: AxisTestContext): errors.append("and by the way: axis reports no error even though there is one") return errors -def test_assert_no_error(axis_ctx: AxisTestContext): +def test_assert_no_error(axis_ctx: ODriveAxisComponent): errors = get_errors(axis_ctx) if len(errors) > 0: raise TestFailed("\n".join(errors)) -def yaml_to_test_objects(test_rig_yaml: dict, logger: Logger): - available_test_objects = {} - - def add_component(component): - available_test_objects[type(component)] = available_test_objects.get(type(component), []) - available_test_objects[type(component)].append(component) - - for component_yaml in test_rig_yaml['components']: - if component_yaml['type'] == 'odrive': - odrv_ctx = ODriveTestContext(component_yaml) - add_component(odrv_ctx) - for enc_ctx in odrv_ctx.encoders: - add_component(enc_ctx) - for axis_ctx in odrv_ctx.axes: - add_component(axis_ctx) - elif component_yaml['type'] == 'generalpurpose': - for (k, v) in [(k, v) for (k, v) in component_yaml.items() if k.startswith("can")]: - can_ctx = CANTestContext({'id': k, 'bus': v}) - add_component(can_ctx) - elif component_yaml['type'] == 'motor': - motor_ctx = MotorTestContext(component_yaml) - add_component(motor_ctx) - else: - logger.warn('test rig has unsupported component ' + component_yaml['type']) - continue - - - return available_test_objects - -def run_shell(command_line, logger, timeout=None): +def run_shell(command_line, logger, env=None, timeout=None): """ Runs a shell command in the current directory """ @@ -192,60 +587,102 @@ def run_shell(command_line, logger, timeout=None): cmd = shlex.split(command_line) result = subprocess.run(cmd, timeout=timeout, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + stderr=subprocess.STDOUT, + env=env) if result.returncode != 0: logger.error(result.stdout.decode(sys.stdout.encoding)) raise TestFailed("command {} failed".format(command_line)) -def program_teensy(hex_file_path, program_gpio: int, logger: Logger): - """ - Programs the specified hex file onto the Teensy. - To reset the Teensy, a GPIO of the local system must be connected to the - Teensy's "Program" pin. This pin must first be manually made available to - user space: - - echo 26 | sudo tee /sys/class/gpio/export - sudo chmod a+rw /sys/class/gpio/gpio26/* - echo out > /sys/class/gpio/gpio26/direction - """ +def get_combinations(param_options): + if isinstance(param_options, tuple): + if len(param_options) > 0: + for part1, part2 in itertools.product( + get_combinations(param_options[0]), + get_combinations(param_options[1:]) if (len(param_options) > 1) else [()]): + assert(isinstance(part1, tuple)) + assert(isinstance(part2, tuple)) + yield part1 + part2 + elif is_list_like(param_options): + for item in param_options: + for c in get_combinations(item): + yield c + else: + yield (param_options,) - # Put Teensy into program mode by pulling it's program pin down - with open("/sys/class/gpio/gpio{}/direction".format(program_gpio), "w") as fp: - fp.write("out") - with open("/sys/class/gpio/gpio{}/value".format(program_gpio), "w") as gpio: - gpio.write("0") - time.sleep(0.1) - with open("/sys/class/gpio/gpio{}/value".format(program_gpio), "w") as gpio: - gpio.write("1") - - run_shell(["teensy_loader_cli", "-mmcu=imxrt1062", "-w", hex_file_path], logger, timeout = 5) - time.sleep(0.5) # give it some time to boot +def select_params(param_options): + # Select parameters from the resource list + # (this could be arbitrarily complex to improve parallelization of the tests) + for combination in get_combinations(param_options): + if all_unique(combination): + return list(combination) -def run(test_cases): - if not isinstance(test_cases, list): - test_cases = [test_cases] + return None - for test_case in test_cases: - # Compile a list of list of potential objects that might be compatible with this - # test - possible_parameters = [] - sig = signature(test_case.is_compatible) - for param_name in sig.parameters: - param_type = sig.parameters[param_name].annotation - possible_parameters.append(available_test_objects[param_type]) +def run(tests): + if not isinstance(tests, list): + tests = [tests] - # For each combination, check if the test is compatible with these objects - for param_combination in itertools.product(*possible_parameters): - if not test_case.is_compatible(*param_combination): + for test in tests: + # The result of get_test_cases can be described in ABNF grammar: + # test-case-list = *arglist + # arglist = *flexible-arg + # flexible-arg = component / *argvariant + # argvariant = component / arglist + # + # If for a particular test-case, the components are not given plainly + # but in some selectable form, the test driver will select exactly one + # of those options. + # In other words, it will bring arglist from the form *flexible-arg + # into the form *component before calling the test. + # + # All of the provided test-cases are executed. If none is provided, + # a warning is reported. A warning is also reported if for a particular + # test case no component combination can be resolved. + + test_cases = list(test.get_test_cases(testrig)) + + if len(test_cases) == 0: + logger.warn('no resources are available to conduct the test {}'.format(type(test).__name__)) + continue + + for test_case in test_cases: + params = select_params(test_case) + if params is None: + logger.warn('no resources are available to conduct the test {}'.format(type(test).__name__)) continue - - for param in param_combination: - param.make_available(logger) - logger.notify('* running {} on {}...'.format(type(test_case).__name__, - [str(p) for p in param_combination])) - test_case.run_test(*param_combination, logger) + logger.notify('* preparing {} with {}...'.format(type(test).__name__, + [(testrig.get_component_name(p) if isinstance(p, Component) else str(p)) for p in params])) + + teensies = set() + for param in params: + if isinstance(param, ProxiedComponent): + param.prepare() + for teensy, _, _, _ in param.gpio_tuples: + teensies.add(teensy) + + for teensy in teensies: + teensy.commit_routing_config(logger) + + # prepare all components + teensies = set() + for param in params: + if isinstance(param, ProxiedComponent): + continue + if hasattr(param, 'prepare'): + param.prepare(logger) + + logger.notify('* running {} on {}...'.format(type(test).__name__, + [(testrig.get_component_name(p) if isinstance(p, Component) else str(p)) for p in params])) + + # Resolve routed components + for i, param in enumerate(params): + if isinstance(param, ProxiedComponent): + params[i] = param.impl + + test.run_test(*params, logger) + logger.success('All tests passed!') @@ -269,19 +706,41 @@ args = parser.parse_args() test_rig_yaml = yaml.load(args.test_rig_yaml, Loader=yaml.BaseLoader) logger = Logger() -available_test_objects = yaml_to_test_objects(test_rig_yaml, logger) +testrig = TestRig(test_rig_yaml, logger) if args.setup_host: - def export_gpio(gpio): - if not os.path.isdir("/sys/class/gpio/gpio{}".format(gpio)): + for gpio in testrig.get_components(LinuxGpioComponent): + num = gpio.num + logger.debug('exporting GPIO ' + str(num) + ' to user space...') + if not os.path.isdir("/sys/class/gpio/gpio{}".format(num)): with open("/sys/class/gpio/export", "w") as fp: - fp.write(str(gpio)) - os.chmod("/sys/class/gpio/gpio{}/value".format(gpio), stat.S_IROTH | stat.S_IWOTH) - os.chmod("/sys/class/gpio/gpio{}/direction".format(gpio), stat.S_IROTH | stat.S_IWOTH) + fp.write(str(num)) + os.chmod("/sys/class/gpio/gpio{}/value".format(num), stat.S_IROTH | stat.S_IWOTH) + os.chmod("/sys/class/gpio/gpio{}/direction".format(num), stat.S_IROTH | stat.S_IWOTH) - # TODO: read configuration from yaml file - export_gpio(20) # connected to Teensy GPIO - export_gpio(26) # connected to Teensy Program pin + for port in testrig.get_components(SerialPortComponent): + logger.debug('changing permissions on ' + port.yaml['port'] + '...') + os.chmod(port.yaml['port'], stat.S_IROTH | stat.S_IWOTH) + + if len(list(testrig.get_components(TeensyComponent))): + # This breaks the annoying teensy loader that shows up on every compile + logger.debug('modifying teensyduino installation...') + if not os.path.isfile('/usr/share/arduino/hardware/tools/teensy_post_compile_old'): + os.rename('/usr/share/arduino/hardware/tools/teensy_post_compile', '/usr/share/arduino/hardware/tools/teensy_post_compile_old') + with open('/usr/share/arduino/hardware/tools/teensy_post_compile', 'w') as scr: + scr.write('#!/bin/bash\n') + scr.write('if [ "$ARDUINO_COMPILE_DESTINATION" != "" ]; then\n') + scr.write(' cp -r ${2#-path=}/*.ino.hex ${ARDUINO_COMPILE_DESTINATION}\n') + scr.write('fi\n') + os.chmod('/usr/share/arduino/hardware/tools/teensy_post_compile', stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH) + + # Bring up CAN interface(s) + for intf in testrig.get_components(CanInterfaceComponent): + name = intf.yaml['interface'] + logger.debug('bringing up {}...'.format(name)) + run_shell('ip link set dev {} down'.format(name), logger) + run_shell('ip link set dev {} type can bitrate 250000'.format(name), logger) + run_shell('ip link set dev {} type can loopback off'.format(name), logger) + run_shell('ip link set dev {} up'.format(name), logger) - os.chmod("/dev/ttyS0", stat.S_IROTH | stat.S_IWOTH) diff --git a/tools/odrive/tests/uart_ascii_test.py b/tools/odrive/tests/uart_ascii_test.py index a4e78a49..71c8bd7d 100644 --- a/tools/odrive/tests/uart_ascii_test.py +++ b/tools/odrive/tests/uart_ascii_test.py @@ -5,13 +5,12 @@ import struct import time import os import io -import serial import functools import operator from fibre.utils import Logger from odrive.enums import * -from test_runner import ODriveTestContext, test_assert_eq, test_assert_no_error, program_teensy +from test_runner import * def append_checksum(command): @@ -32,28 +31,29 @@ def reset_state(ser): ser.flushInput() # discard response class TestUartAscii(): - def is_compatible(self, odrive: ODriveTestContext): - return True + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + ports = list(testrig.get_connected_components({ + 'rx': (odrive.gpio1, True), + 'tx': (odrive.gpio2, False) + }, SerialPortComponent)) + yield (odrive, ports) - def run_test(self, odrive: ODriveTestContext, logger: Logger): + def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, logger: Logger): """ Tests the most important functions of the ASCII protocol. """ - # Disable noise - with open("/sys/class/gpio/gpio{}/direction".format(20), "w") as fp: - fp.write("out") - with open("/sys/class/gpio/gpio{}/value".format(20), "w") as gpio: - gpio.write("0") - - hexfile = 'uart_pass_through.ino.hex' - program_teensy(os.path.join(os.path.dirname(__file__), hexfile), 26, logger) - time.sleep(1.0) + if (odrive.handle.config.gpio1_pwm_mapping.endpoint != (0,0)) or (odrive.handle.config.gpio2_pwm_mapping.endpoint != (0,0)): + logger.debug('UART pins in use. Reconfiguring...') + odrive.handle.config.gpio1_pwm_mapping.endpoint = None + odrive.handle.config.gpio2_pwm_mapping.endpoint = None + odrive.save_config_and_reboot() odrive.handle.axis0.config.enable_step_dir = False odrive.handle.config.enable_uart = True - with serial.Serial('/dev/ttyS0', 115200, timeout=1) as ser: + with port.open(115200) as ser: # reset port to known state reset_state(ser) @@ -159,84 +159,24 @@ class TestUartAscii(): # TODO: test cases for 't', 'ss', 'se', 'sr' commands - -class TestUartNoise(): - def is_compatible(self, odrive: ODriveTestContext): - return True - - def run_test(self, odrive: ODriveTestContext, logger: Logger): - """ - Tests if the UART can handle invalid signals. - """ - - # Disable noise - with open("/sys/class/gpio/gpio{}/direction".format(20), "w") as fp: - fp.write("out") - with open("/sys/class/gpio/gpio{}/value".format(20), "w") as gpio: - gpio.write("0") - - hexfile = 'uart_pass_through.ino.hex' - program_teensy(os.path.join(os.path.dirname(__file__), hexfile), 26, logger) - time.sleep(1.0) - - odrive.handle.axis0.config.enable_step_dir = False - odrive.handle.config.enable_uart = True - - with serial.Serial('/dev/ttyS0', 115200, timeout=1) as ser: - # reset port to known state - reset_state(ser) - - # Enable square wave of ~1.6MHz on the ODrive's RX line - with open("/sys/class/gpio/gpio{}/value".format(20), "w") as gpio: - gpio.write("1") - - time.sleep(0.1) - reset_state(ser) - - # Read an attribute (should fail because the command is not passed through) - ser.write(b'r vbus_voltage\n') - test_assert_eq(ser.readline(), b'') - - # Disable square wave - with open("/sys/class/gpio/gpio{}/value".format(20), "w") as gpio: - gpio.write("0") - - # Give receiver some time to recover - time.sleep(0.1) - - # reset port to known state - reset_state(ser) - - # Try again - ser.write(b'r vbus_voltage\n') - response = float(ser.readline().strip()) - test_assert_eq(response, odrive.handle.vbus_voltage, accuracy=0.1) - - - class TestUartBurnIn(): - def is_compatible(self, odrive: ODriveTestContext): - return True + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + ports = list(testrig.get_connected_components({ + 'rx': (odrive.gpio1, True), + 'tx': (odrive.gpio2, False) + }, SerialPortComponent)) + yield (odrive, ports) - def run_test(self, odrive: ODriveTestContext, logger: Logger): + def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, logger: Logger): """ Tests if the ASCII protocol can handle 64kB of random data being thrown at it. """ - # Disable noise - with open("/sys/class/gpio/gpio{}/direction".format(20), "w") as fp: - fp.write("out") - with open("/sys/class/gpio/gpio{}/value".format(20), "w") as gpio: - gpio.write("0") - - hexfile = 'uart_pass_through.ino.hex' - program_teensy(os.path.join(os.path.dirname(__file__), hexfile), 26, logger) - time.sleep(1.0) - odrive.handle.axis0.config.enable_step_dir = False odrive.handle.config.enable_uart = True - with serial.Serial('/dev/ttyS0', 115200, timeout=1) as ser: + with port.open(115200) as ser: with open('/dev/random', 'rb') as rand: buf = rand.read(65536) ser.write(buf) @@ -250,9 +190,81 @@ class TestUartBurnIn(): test_assert_eq(response, odrive.handle.vbus_voltage, accuracy=0.1) +class TestUartNoise(): + def get_test_cases(self, testrig: TestRig): + for odrive in testrig.get_components(ODriveComponent): + # For every ODrive, find a connected serial port which has a teensy + # in between, so that we can inject noise, + + ports = list(testrig.get_connected_components({ + 'rx': (odrive.gpio1, True), + 'tx': (odrive.gpio2, False) + }, SerialPortComponent)) + + # Hack the bus objects to enable noise_enable functionality on the TX line. + + def get_noise_gpio(bus): + teensy = bus.gpio_tuples[1][0] + for teensy_gpio in teensy.gpios: + for other_gpio in testrig.get_directly_connected_components(teensy_gpio): + if isinstance(other_gpio, LinuxGpioComponent): + return teensy_gpio, other_gpio + return None + + for idx, bus in enumerate(ports): + noise_gpio_on_teensy, noise_gpio_on_rpi = get_noise_gpio(bus) + assert(noise_gpio_on_rpi) + t, i, o, _ = bus.gpio_tuples[1] + bus.gpio_tuples[1] = (t, i, o, noise_gpio_on_teensy) + ports[idx] = (bus, noise_gpio_on_rpi) + + yield (odrive, ports) + + def run_test(self, odrive: ODriveComponent, port: SerialPortComponent, noise_enable: LinuxGpioComponent, logger: Logger): + """ + Tests if the UART can handle invalid signals. + """ + noise_enable.config(output=True) + noise_enable.write(False) + time.sleep(0.1) + + odrive.handle.axis0.config.enable_step_dir = False + odrive.handle.config.enable_uart = True + + with port.open(115200) as ser: + # reset port to known state + reset_state(ser) + + # Enable square wave of ~1.6MHz on the ODrive's RX line + noise_enable.write(True) + + time.sleep(0.1) + reset_state(ser) + + time.sleep(1.0) + + # Read an attribute (should fail because the command is not passed through) + ser.write(b'r vbus_voltage\n') + test_assert_eq(ser.readline(), b'') + + # Disable square wave + noise_enable.write(False) + + # Give receiver some time to recover + time.sleep(0.1) + + # reset port to known state + reset_state(ser) + + # Try again + ser.write(b'r vbus_voltage\n') + response = float(ser.readline().strip()) + test_assert_eq(response, odrive.handle.vbus_voltage, accuracy=0.1) + + if __name__ == '__main__': test_runner.run([ TestUartAscii(), - TestUartNoise(), TestUartBurnIn(), + TestUartNoise(), ]) diff --git a/tools/odrive/tests/uart_pass_through.ino.hex b/tools/odrive/tests/uart_pass_through.ino.hex deleted file mode 100644 index 8175c58e..00000000 --- a/tools/odrive/tests/uart_pass_through.ino.hex +++ /dev/null @@ -1,786 +0,0 @@ -:0200000460009A -:100000004643464200000156000000000101020084 -:1000100000000000000000000000000000000000E0 -:1000200000000000000000000000000000000000D0 -:1000300000000000000000000000000000000000C0 -:1000400000000000010403000000000000000000A8 -:100050000000200000000000000000000000000080 -:100060000000000000000000000000000000000090 -:100070000000000000000000000000000000000080 -:10008000EB04180A063204260000000000000000FD -:10009000050404240000000000000000000000002F -:1000A0000000000000000000000000000000000050 -:1000B0000604000000000000000000000000000036 -:1000C0000000000000000000000000000000000030 -:1000D00020041808000000000000000000000000DC -:1000E0000000000000000000000000000000000010 -:1000F0000000000000000000000000000000000000 -:10010000D8041808000000000000000000000000F3 -:100110000204180804200000000000000000000095 -:1001200000000000000000000000000000000000CF -:10013000600400000000000000000000000000005B -:1001400000000000000000000000000000000000AF -:10015000000000000000000000000000000000009F -:10016000000000000000000000000000000000008F -:10017000000000000000000000000000000000007F -:10018000000000000000000000000000000000006F -:10019000000000000000000000000000000000005F -:1001A000000000000000000000000000000000004F -:1001B000000000000000000000000000000000003F -:1001C000000100000010000001000000000000001D -:1001D000000001000000000000000000000000001E -:1001E000000000000000000000000000000000000F -:1001F00000000000000000000000000000000000FF -:10020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE -:10021000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE -:10022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE -:10023000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE -:10024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE -:10025000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE -:10026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E -:10027000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E -:10028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E -:10029000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E -:1002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E -:1002B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E -:1002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E -:1002D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E -:1002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E -:1002F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E -:10030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD -:10031000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED -:10032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD -:10033000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD -:10034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD -:10035000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD -:10036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D -:10037000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D -:10038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D -:10039000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D -:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D -:1003B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D -:1003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D -:1003D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D -:1003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D -:1003F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D -:10040000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC -:10041000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC -:10042000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC -:10043000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC -:10044000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC -:10045000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC -:10046000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C -:10047000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C -:10048000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C -:10049000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C -:1004A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C -:1004B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C -:1004C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C -:1004D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C -:1004E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C -:1004F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C -:10050000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB -:10051000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB -:10052000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB -:10053000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB -:10054000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB -:10055000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB -:10056000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B -:10057000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B -:10058000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B -:10059000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B -:1005A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B -:1005B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B -:1005C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B -:1005D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B -:1005E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B -:1005F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B -:10060000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA -:10061000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA -:10062000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA -:10063000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA -:10064000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA -:10065000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA -:10066000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A -:10067000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A -:10068000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A -:10069000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A -:1006A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A -:1006B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A -:1006C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A -:1006D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A -:1006E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A -:1006F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A -:10070000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 -:10071000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 -:10072000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 -:10073000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 -:10074000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 -:10075000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 -:10076000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 -:10077000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 -:10078000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 -:10079000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 -:1007A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 -:1007B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 -:1007C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 -:1007D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 -:1007E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 -:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 -:10080000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 -:10081000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 -:10082000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 -:10083000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 -:10084000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 -:10085000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 -:10086000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 -:10087000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 -:10088000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 -:10089000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 -:1008A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 -:1008B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 -:1008C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 -:1008D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 -:1008E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 -:1008F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 -:10090000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 -:10091000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 -:10092000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 -:10093000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 -:10094000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 -:10095000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 -:10096000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 -:10097000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 -:10098000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 -:10099000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 -:1009A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 -:1009B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 -:1009C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 -:1009D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 -:1009E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 -:1009F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 -:100A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 -:100A1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 -:100A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 -:100A3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 -:100A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 -:100A5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 -:100A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 -:100A7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 -:100A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 -:100A9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 -:100AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 -:100AB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 -:100AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 -:100AD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 -:100AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 -:100AF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 -:100B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 -:100B1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 -:100B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 -:100B3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 -:100B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 -:100B5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 -:100B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 -:100B7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 -:100B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 -:100B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 -:100BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 -:100BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 -:100BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 -:100BD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 -:100BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 -:100BF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 -:100C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 -:100C1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 -:100C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 -:100C3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 -:100C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 -:100C5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 -:100C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 -:100C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 -:100C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 -:100C9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 -:100CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 -:100CB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 -:100CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 -:100CD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 -:100CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 -:100CF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 -:100D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 -:100D1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 -:100D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 -:100D3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 -:100D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 -:100D5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 -:100D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 -:100D7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 -:100D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 -:100D9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 -:100DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 -:100DB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 -:100DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 -:100DD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 -:100DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 -:100DF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 -:100E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 -:100E1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 -:100E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 -:100E3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 -:100E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 -:100E5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 -:100E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 -:100E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 -:100E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 -:100E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 -:100EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 -:100EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 -:100EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 -:100ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 -:100EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 -:100EF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 -:100F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 -:100F1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 -:100F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 -:100F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 -:100F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 -:100F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 -:100F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 -:100F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 -:100F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 -:100F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 -:100FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 -:100FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 -:100FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 -:100FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 -:100FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 -:100FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 -:10100000D10020402C100060000000000000000013 -:1010100020100060001000600000000000000000D0 -:1010200000000060E030000000000000000001202F -:1010300035100060764B0720764C4FF42A01764A33 -:101040005C64186499639546744A75498A420FD066 -:10105000744B9A420CD2D4430846234423F0030332 -:1010600004330B4450F8041B984242F8041BF9D196 -:101070006D4A6E498A420FD06D4B9A420CD2D443CE -:101080000846234423F0030304330B4450F8041BA5 -:10109000984242F8041BF9D1664A674B9A420BD238 -:1010A000D04311460024034423F0030304331344C4 -:1010B00041F8044B8B42FBD1604A4FF47001604B06 -:1010C000116003F530715F4A43F8042F9942FBD158 -:1010D0005D4B80215D4A03F8011B9342FBD15C4CC0 -:1010E0004FF080375B4E4FF0FF32DFF8A8A10025AC -:1010F000DFF8A491DFF8A481574B4549C3F800A05D -:10110000C4F80471C4F80091C4F8F470C4F8F08015 -:10111000F36923F07F0343F04003F361736A23F024 -:101120007F0343F0400373628A66CA660A674A67B0 -:1011300000F0B6F8494A6320494B4A49106003223F -:101140001D60CAF8381043F8082C4749474A4848F8 -:10115000C3F8082D0B68474A43F08073CAF83C0077 -:1011600045480B601368454943F001031360036869 -:101170000B6000F0E5F8C4F804714148C4F8009130 -:10118000C4F8F470C4F8F08000F056FA00BF00BF55 -:1011900000BF00BFF16E3B4A41F440513A4BF1664B -:1011A0001560C2F80851C2F81851C2F82851C2F8A7 -:1011B00038519A6BD20708D442F615623349596503 -:1011C0001A659A6B42F001029A632F4A304C936879 -:1011D00043F00113936000F013FA2368132BFCD93A -:1011E00000F05CF900F0D0F900F012FA00F0DAF843 -:1011F00000F00AFA2368B3F5967FFBD300F020FADB -:1012000000F012FA00F0F4F900F0F6F9FAE700BF86 -:1012100000C00A40ABAAAAAA008007200000000074 -:1012200050160060D016000000000020242D006041 -:10123000C0030020C0030020C032002088ED00E081 -:10124000FC0F00201102000000E400E0A0E400E038 -:1012500000800D4000C00F4008ED00E014E000E009 -:1012600018E000E0890D0000FCED00E00000202007 -:101270008D0E0000001000E0041000E0840D00203E -:101280000046C3230040084000400D400000C05607 -:10129000880D0020001000201B1018200C0D1113C9 -:1012A000F0B5194A0021194B4FF0100E18480124CF -:1012B000184E194D0160194FC2F800E01E6015600C -:1012C000174E184D1F601660174F1D60174E184DB2 -:1012D00017601E60174F1560174E184D1F6016607F -:1012E0001D600460BFF34F8FBFF36F8FC3F8B01161 -:1012F000BFF34F8FBFF36F8F52F8883C43F44033F6 -:1013000042F8883CF0BD00BF9CED00E0A0ED00E09D -:1013100094ED00E0250008031100200021000207E1 -:1013200012000020250008131300202027000B13B3 -:101330001400004033001013150000602F000B074D -:10134000F0B4174A40274FF480314FF480564FF4E1 -:1013500000554FF4404443F24200136913F0020F6A -:1013600006D0946151619061136913F0020FF8D1B6 -:1013700013F4005F01D15561EFE713F4805F01D1F1 -:101380005661EAE7002BE8DA13F4803F01D091615F -:10139000E3E75B0601D45761DFE7F0BC704700BFAD -:1013A00000800D40364A03203649F3EE096A13687F -:1013B00023F00103F0B51360C2F89000D1F8E030DB -:1013C000DFF8D4E0DCB2C3F30B202F4FC0EB135394 -:1013D00007EE904AA4F15501CEF80040B8EEE77A46 -:1013E00003EB830407EE900A03FB01F13B6003EB80 -:1013F0008313B8EEE75A07EE901A091B77EE666A78 -:10140000B8EE677A214D07EE901A0B44C5ED006ADD -:10141000F8EE677A1E4EC7EE265A1E4930601068F5 -:1014200087EEA66A07EE903AF8EE677A87EEA67A1C -:1014300075EE855A76EE056AFCEEE55AFCEEE66A34 -:1014400015EE903A40EA035316EE900A77EE057ACD -:10145000136001EA0041D2F81031FCEEE77A0B4349 -:10146000C2F8103117EE903AD2F81011C3F30B0303 -:101470000B43C2F81031136843F002031360F0BD50 -:1014800080810D4000441F40F0030020EC03002049 -:10149000F40300200000FF0FE8030020304B40F66B -:1014A000617270B5C3F8202140F2044500F0B8F82D -:1014B0002C492D48D1F880202C4C42F003022C4BB3 -:1014C000C1F88020C0F86051226813401BB9D0F8E1 -:1014D000A8319A071AD0244B4FF00041234A516398 -:1014E0001A46D3F8401141F00201C3F84011D2F876 -:1014F00040319B07FBD44FF400301E491B4B4FF08B -:101500000042086019209A6300F092F81A4D0022F8 -:10151000164B4FF08041144C0A26996328461A60F6 -:101520001146C4F8A8614FF4207200F075F84FF42A -:1015300081064FF4800040F24313104A10492E6098 -:101540002864C4F85851C2F80412C4F848310D4A4E -:101550004FF4003101231160C4F8403170BD00BF69 -:1015600000800D4000C00F4000002E4000900D4054 -:10157000001C1E008CE200E0003000200010002063 -:10158000ED0300000CE100E0114B1249D86E0A4651 -:1015900040F4403030B4D86640F2B765D86EA0242D -:1015A00040F44070D8664D648C64936C1B06FCD488 -:1015B000094B40F2B760A021064A58649964936CC5 -:1015C00013F08003FBD1054A137030BC704700BF95 -:1015D00000C00F4000400C4000800C40810D0020F6 -:1015E000F8B500BFF8BC08BC9E467047FFFFFFFF80 -:1015F0005FF800F0B10000005FF800F0AD0E0000F1 -:101600005FF800F0290200005FF800F02D020000F2 -:101610005FF800F0F11200005FF800F02D160000F6 -:101620005FF800F0ED0A00005FF800F0AD00000088 -:101630005FF800F0E11100005FF800F04D0F0000CE -:101640005FF800F0DD150000450000001501000006 -:10165000000000000000000000000000000000008A -:10166000000000000000000000000000000000007A -:1016700010B5054C237833B9044B13B10448AFF3CC -:1016800000800123237010BDC00300200000000073 -:10169000D4160000084B10B51BB108490848AFF339 -:1016A00000800848036803B910BD074B002BFBD02E -:1016B000BDE81040184700BF00000000C403002030 -:1016C000D4160000C00300200000000008B5084B3D -:1016D0000121187800F084F8064B0121187800F0F9 -:1016E0007FF8054B00211878BDE8084000F078B875 -:1016F000DC030020F0020020EC020020FFF7E6BF30 -:10170000124B70B5187800F065F8114B114C054676 -:10171000187800F05FF823780F4A064683F001033B -:101720001078237000F056F80C4B50B931461878F9 -:1017300000F04AF80A4B29461878BDE8704000F0DE -:1017400043B82178187800F03FF8F3E7E40300206D -:10175000F8020020E0030020EC020020DC0300205F -:10176000F0020020044A054B106805491A68054B31 -:1017700008601A60704700BFFC020020F4020020DD -:10178000E4030020DC0300200001074B1A181B585B -:10179000D2685868104202D011B9C3F88820704747 -:1017A000C3F88420704700BF000000200001054BF3 -:1017B0001A5819189268CB681A4214BF01200020E9 -:1017C000704700BF00000020272801D8FFF7DCBFCA -:1017D000704700BF272801D8FFF7E8BF00207047F7 -:1017E00027281CD800011A4A012902EB00031058CF -:1017F00010B415D0042913D0DC68426822EA040230 -:1018000042609A68E9B102291ED003295B685DF83D -:10181000044B0CBF0F491049116015221A60704724 -:10182000DA680129446842EA040242609A6808D0F2 -:1018300040F6380111605B6815225DF8044B1A60B0 -:10184000704738211160F6E704491160F3E700BFE3 -:1018500000000020383001003800010038F001009D -:1018600004207146084203D0EFF3098000F008B865 -:10187000EFF3088000F004B8704700BF704700BF66 -:101880001B4B05211B4A382030B5C2F848110821EE -:10189000C2F8380383B05A68174C0A4317485A6095 -:1018A000C3F88410C3F888102368834202D914480F -:1018B00000F074FE0E4D08240020124A1249C5F8AB -:1018C00084400190019B934205D8019B0133019311 -:1018D000019B9342F9D9C5F888400190019B8B4246 -:1018E000EDD8019B01330193019B8B42F9D9E6E7C7 -:1018F00000C01B4000801F40B4030020FF45C323ED -:1019000000A3E1113F420F003F548900836B30B4C4 -:101910001BB1536843F40043536072B6446B9CB1EF -:10192000104B2260D3F8B0410C4217D1D3F840419C -:1019300044F48044C3F84041D3F8B851D3F840414F -:101940006404F3D5294209D10023064C8260C360A8 -:10195000D4F8B0311943C4F8B0110263426362B6DF -:1019600030BC704700002E4038B50546036B06E0DA -:10197000AA6B1C6890476A6B2346944208D01846AD -:1019800033B1012B04D05A681206F1D52B6338BD50 -:1019900000232B636B6338BDF0B5F1B9224C2349AA -:1019A0000020234B01228025A1600A601A464D6069 -:1019B000E060D3F8BC41886044F001141D4DC3F8C9 -:1019C000BC41D3F8B01141F00101C3F8B011286057 -:1019D000D2F8B031002BFBD1F0BD0904164B144DE9 -:1019E0000126114C41F0800100221E60596000F573 -:1019F000805CE26400F5005EA36400F54057D5F812 -:101A0000B01100F580462A46986041F48031C3F851 -:101A10000CC0C3F810E05F619E61C5F8B011D2F848 -:101A2000B031002BFBD1BAE700300020202000208D -:101A300000002E4004040020002000202DE9F04F7B -:101A4000BB4C83B0D4F8448118F0010FC4F8448132 -:101A50005ED0D4F8AC31002B55D04FF00119DFF82F -:101A6000F0B22646B34FCA46B96AFA6AC4F8AC3136 -:101A7000D4F8403143F40053C4F84031D4F8403135 -:101A80009D04F5D5D6F8403123F40053C6F8403113 -:101A9000C6F8B4A1D4F8B43113F00113FAD188B266 -:101AA00040F28165CBF80030A84200F29680B0F594 -:101AB000D06F80F0D881B0F5817F00F0578100F2BF -:101AC000D580802800F02681822840F0C78092B21D -:101AD00002F07F01072900F2C18089009648974DE6 -:101AE0000844016810062B706B7040F1E581C90352 -:101AF00001D501232B7002219048FFF74DFFD4F848 -:101B0000AC31002BB0D18A4AD2F8BC31002B44D181 -:101B100018F0400F18D0864BD3F8AC111A46C3F812 -:101B2000AC11D3F8BC11C3F8BC11D2F8B041804B52 -:101B3000002CFAD14FF0FF32C3F8B421D3F884312E -:101B400000F074FB7E4B1C6018F0807F03D07D4B4F -:101B50001B6803B1984718F0007F03D07A4B1B68CD -:101B600003B1984718F0040F02D0714BD3F88431B9 -:101B70006F4BD3F8482112060CD518F0800F09D00E -:101B800072490A78002A00F08E81531EDBB20B7076 -:101B900003B9FBBE03B0BDE8F08F6D49C2F8BC319C -:101BA0000868034240F0CC81654A14681C40AFD0FD -:101BB000630700F1E281670300F1EF81260700F17E -:101BC000E881250300F1E181E00600F1DA81E1021C -:101BD0009ED56048FFF7C8FE9AE742F22105A84269 -:101BE00038D06FD8B0F5086F00F02F81B0F5106FC6 -:101BF00034D1C1F30741584A584811705849594ADD -:101C00000193C6F8C801C6F8CC11C6F8D02100F07F -:101C10000FFB554A019B80210120FB64106051603D -:101C2000D6F8BC11936041F00111BA64C6F8BC113A -:101C3000D6F8B02142F48032C6F8B021444A13608D -:101C4000D4F8B031002BFBD1D4F8AC31002B7FF4A9 -:101C50000BAF58E7100C072800F03281C4F8C09190 -:101C6000D4F8AC31002B7FF4FFAE4CE740F20235E4 -:101C7000A84200F0B780B0F5A06FEFD13A4A8020BB -:101C80000125FB6450601560D6F8BC01936040F0FC -:101C90000113BA64C6F8BC31D6F8B03143F48033CE -:101CA000C6F8B031D4F8B031002BFBD10B0C5B0679 -:101CB00043F08073C6F85431D4F8AC31002B7FF474 -:101CC000D3AE20E742F22123984200F0828042F214 -:101CD00021339842C2D1244B012180221960002176 -:101CE0005A60D4F8BC21BB6442F001129960F964D7 -:101CF000C4F8BC21D4F8B03143F48033C4F8B03117 -:101D0000D4F8B031002BFBD1D4F8AC31002B7FF4E8 -:101D1000ABAEF8E6094A0221104613705370FFF784 -:101D20003BFED4F8AC31002B7FF49EAEEBE600BF57 -:101D300000002E4000300020C0012E40180400207A -:101D4000FC030020F8030020000400200804002009 -:101D50000404002040320020280400200200CC00AF -:101D6000C80002000200C8002020002092B202F049 -:101D70007F03072B3FF672AF12F0800F4FEA830309 -:101D8000884A4FF001011A44136814BF23F48033CA -:101D900023F0010313608022834B196000215A60F5 -:101DA000D4F8BC21BB6442F001129960F964C4F814 -:101DB000BC21D4F8B03143F48033C4F8B031D4F846 -:101DC000B031002BFBD1D4F8AC31002B7FF44CAEFA -:101DD00099E6764BC1F30741754A1868754B106058 -:101DE000197078E792B202F07F03072B3FF636AF07 -:101DF00012F0800F4FEA83036A4A4FF001011A4440 -:101E0000136814BF43F4803343F00103136080224E -:101E1000654B196000215A60D4F8BC21BB6442F0C4 -:101E200001129960F964C4F8BC21D4F8B03143F4CC -:101E30008033C4F8B031D4F8B031002BFBD1D4F8E2 -:101E4000AC31002B7FF410AE5DE65B4A01215B4BA9 -:101E5000127818461A70FFF79FFDD4F8AC31002BAA -:101E60007FF402AE4FE6564B586800283FF4F6AEBA -:101E7000090C1FFA82FE04E00C33586800283FF476 -:101E8000EDAE1D888D42F7D15D887545F4D1090A04 -:101E9000120C03290CBF01781989914228BF114601 -:101EA000FFF77AFD2BE6D3F8482122F08002C3F831 -:101EB000482103B0BDE8F08FCA077FF51CAE18E6D5 -:101EC000404D0120FB6029603F4B4049186059603C -:101ED0003F49D6F8B0016A6001F5005E40F00102AA -:101EE000A1F5005001F58055BB609860A1F58050C8 -:101EF000D860C6F8B02119615D61C3F818E0D4F864 -:101F0000B031002BFBD1284A012048F28001FB644C -:101F100010604FF480305160D6F8BC11936041F0EE -:101F20000113BA64C6F8BC31D6F8B0310343C6F821 -:101F3000B031CBF80000D4F8B031002BFBD1DEE596 -:101F4000204C42F22100002524880D6084427FF459 -:101F50002BAE2049204C03C90D0C86282060A1809F -:101F6000A5717FF421AED2F8481150241B4841F0EE -:101F70008001C2F84811047016E61948FFF7F4FC16 -:101F800019E61848FFF7F0FC21E61748FFF7ECFCCC -:101F90001AE61648FFF7E8FC13E61548FFF7E4FCDD -:101FA0000CE600BFC0012E4020200020880D00203C -:101FB00088320020600D0020280400201804002032 -:101FC0008002002010040020002000208000070074 -:101FD000202400202004002080320020080400205B -:101FE0000031002000320020C0310020803100206C -:101FF00040310020002AA0F102022DE9F04714BF71 -:1020000000274FF00057022A01D9BDE8F0874FEAB8 -:10201000C01ADFF840900D4604460AEB090600217D -:1020200040229846304600F029FE012047EA05414B -:102030004AF80910C6F83880B060B8F1000FE4D053 -:10204000034BA0401C6820431860BDE8F08700BF28 -:10205000FC03002000300020002AA0F102022DE93C -:10206000F04714BF00274FF00057022A01D9BDE8FE -:10207000F0874022C501DFF84490884615440021CE -:1020800004461E4605EB090A504600F0F7FD012202 -:1020900047EA084145F80910CAF83860CAF808202C -:1020A000002EE4D004F11000034B82401868024374 -:1020B0001A60BDE8F08700BFFC030020003000205C -:1020C00012048160C36142F08002F0B442600127D3 -:1020D00001F5805601F5005501F5405401F58042A7 -:1020E0000760C660056144618261F0BC704700BF53 -:1020F000831E022B00D9704730B4064B00F1100448 -:1021000001250A4603EBC01005FA04F130BCFFF7C5 -:10211000FDBB00BF40300020831E022B00D970475A -:1021200010B4054B01240A4604FA00F103EBC01079 -:102130005DF8044BFFF7EABB00300020124A134B56 -:10214000D2F8200220F07F40984210B584B002D827 -:1021500000EB800040000E4C01A90A2200F0C8FBF1 -:1021600001A90023204611F8012B01333AB10A2BB3 -:1021700020F8022FF7D11623237004B010BD5B00A6 -:10218000DBB2237004B010BD00441F407F9698005E -:10219000980300204368C269C3F30E43054930B475 -:1021A000C3F14003044C002521F8123024F81250EA -:1021B00030BC7047F80B0020F00B0020F8B5154B31 -:1021C0001B783BB903F0FF04134B1B7813B1134D7D -:1021D0002A8802B9F8BD124F2346124EC2F580720A -:1021E0003978114806EB411600EB01213046FFF724 -:1021F00067FF31460420FFF77BFF3B780133DBB2FA -:10220000062B98BF3B704FF0000388BF3C702B80BB -:10221000F8BD00BF2C0B002028040020600C00201B -:102220002D0B0020800C00202C040020704700BFE4 -:102230000021E0222048F8B50C46204E204D00F049 -:102240001DFD204F2146204B6022347028461F4E32 -:102250001C8000F013FD23462246102102203C6022 -:10226000BC803460B480FFF7F7FE2246184B402153 -:102270000320FFF7BFFE2346224640210420FFF73C -:10228000EBFE2346402228461249FFF719FF294654 -:102290000320FFF741FF104B4A2210491048086005 -:1022A000C3F88440C3F88020D3F8482142F08072FC -:1022B000C3F84821F8BD00BF800C00202D0B002082 -:1022C000000C0020F80B0020600C0020F00B002018 -:1022D000450B0000300B002000002E40F8030020CA -:1022E0006D0B0000024A034B10881B88C01A704710 -:1022F000F80B0020F00B002010B4EFF3108272B640 -:10230000437F33B9017F012908D0032910D001236D -:10231000437702B962B65DF8044B7047114C2168EF -:10232000A1B1114943610B68086083615861EEE710 -:102330000E4C216881B10E4943610B6808608361CE -:1023400058610C4B4FF080511960E0E7064B41613A -:10235000816120601860DAE7054B4161816120608E -:102360001860EEE7740D0020700D0020640D002051 -:10237000680D002004ED00E010B4047F4160022CE1 -:10238000C26003D05DF8044BFFF7B6BF83685DF809 -:10239000044B184770B5EFF3108172B60C4C2368EC -:1023A0008BB10C4E00255A6922607AB1956101B952 -:1023B00062B65D7718469B689847EFF3108172B656 -:1023C0002368002BEFD101B962B670BD3260EEE731 -:1023D000640D0020680D0020FFF7DCBF184A30B400 -:1023E0001468002C28D0036821688B420FD2CB1AC6 -:1023F00000218460C1602360E0601060022330BC73 -:10240000037570470360144611688B4208D3A268B5 -:102410005B1A002AF6D18260C4600360A060EDE719 -:10242000D568CB1A82600222C560E060C16888600E -:102430002360027530BC70478460C4601060DDE7C3 -:102440006C0D0020F8B5224E34682CB32368002BA5 -:102450003AD11D461F4F04E03468ECB12368002BCD -:1024600032D1A36803B1DD6020693360036825754C -:102470001B68BB4221D1037F4560022BC46020D082 -:10248000FFF73AFF6368002BE6D023602046FFF792 -:10249000A5FF3468002CE1D1EFF3108372B60E4A29 -:1024A00000211068116003B962B628B18468FFF793 -:1024B00095FF20460028F9D1F8BD22460021984713 -:1024C000E0E783689847DDE7013B2360E4E700BF6E -:1024D0006C0D0020290D00007C0D0020044A054BE6 -:1024E0001168054A1960136801331360FFF7AABF2A -:1024F000041000E0840D0020880D002070B5214CF0 -:10250000237883B9204B01221B7822701BBB1F4B01 -:102510001B78002B29D11E4B00211A68217012B1A3 -:10252000EFF3058202B170BDEFF3108072B61A6846 -:10253000F2B1184C2178D9B90126556926701D6071 -:10254000D5B1A96100B962B60025936810465577E8 -:102550009847257070BDFFF7C5FE0028D7D000F062 -:102560005FFB0A4B1B78002BD5D000F045FBD2E770 -:102570000028D8D162B670BD074B1D600028E3D19A -:10258000E1E700BF800D0020B8030020A80D002067 -:10259000740D0020780D0020700D00208C4A8D4BAA -:1025A00090422DE9F0438C4D5C699969EF681DD923 -:1025B0008A4B984240F20181894B40F22766DFF84E -:1025C00060E20344874D1A0AAEFB0232D30903EBE3 -:1025D000830303EB830202F2E243B34228BF334694 -:1025E000A3F54873A5FB0336F60804E07E4EB0421F -:1025F00094BF06260E26774A07F01F0ED2F88030C9 -:10260000B64543F0C003C2F880300AD2724B27F0BF -:102610001F071A463743DF601368002BFCDA07F008 -:102620001F0E14F000732ED1704D714AD5F810C0F2 -:1026300015460CEA0202AA420ABF4FF0C0534FF4FB -:102640008052002284EA030515F0605F06D024F072 -:10265000605403F060535F4D1C436C6181EA0203D8 -:1026600013F4405F08D05B4B21F4405111431A46EC -:102670009961936C1D07FCD444F00074554A546171 -:10268000936C9906FCD401215A4D0A4601FB02F3D2 -:1026900000FB03F3AB4209D8072A00F28480013221 -:1026A00001FB02F300FB03F3AB42F5D95248534D53 -:1026B0001844A5FB0030030D6C2B79D8352B7ED840 -:1026C000DFF8608136234E48DFF820C14D4DDCF83D -:1026D0000090B0FBF2F009EA05054545B0FBF1F0CA -:1026E0000BD043F400534FF480586546CCF800807B -:1026F000CCF800302B68002BFCDADFF8D8C0013AA8 -:10270000DCF8103003F00703934207D002F0070211 -:102710006546CCF81020AB6CDB03FCD40139890290 -:1027200084EA010313F4E05F0AD02A4B24F4E05456 -:1027300001F4E0511A460C435C61936C9907FCD498 -:10274000314B32490344DB09A1FB0331090B042956 -:1027500028BF04214B1E1B0284EA030212F4407FAF -:1027600006D024F4407403F440731A4A1C435461A5 -:10277000184B24F000741A465C61936C9B06FCD4E1 -:10278000B0FBF1F1224A7645224B1060196008D265 -:10279000114B27F01F071A463743DF601368002BE1 -:1027A000FCDABDE8F083042980D8013101226DE70D -:1027B000DFF874806C23184886E712261BE7174859 -:1027C000DFF8688000FB03F043EA08087CE700BFFD -:1027D00000A4781F00C00F40000008400046C3233B -:1027E00000BA3CDC1F85EB5100366E0100800D40C5 -:1027F00040300080FFB19F26808D5B00819F5E1678 -:1028000000B29F267F3001807FD1F0089F10E50045 -:10281000B4030020B003002000643F4D001BB7004C -:1028200023B24C00362000806C2000800020008005 -:10283000002852D02DE9F04F814683B0274C01206B -:10284000274D284E54E8003F2A68316844E80003C9 -:10285000002BF7D1244F4FF47A7E2448D7F800C0DC -:10286000BB4607F1C6470368C1EB0C0107F5DE174D -:1028700007F67F67A7FB03C3BA4601279B0CB1FB92 -:10288000F3F30EFB023854E8003F2A68316844E84D -:102890000073002BF7D1DBF800C04FF47A7E036899 -:1028A0000EFB02F2C1EB0C01AAFB033EC8EB0203D4 -:1028B0004FEA9E42B1FBF2F1CA18B2F57A7F07D314 -:1028C000B9F1010908F57A78DDD103B0BDE8F08FE0 -:1028D0000190FFF713FE0198D5E770478C32002076 -:1028E000880D0020840D0020041000E0B4030020B7 -:1028F000F0B44E1E0025374600E00135B0FBF2F380 -:1029000002FB130000F13704092800F13000E4B2A3 -:1029100098BFC4B2184607F8014F002BEDD14A19F1 -:1029200053704DB1013316F8014F1778E81A37701C -:10293000834202F80149F5DB0846F0BC704700BF4E -:10294000A4484FF00F0CA44B826F42F47F02F0B505 -:1029500082670025D0F880204FF470469F4C4FF4DA -:10296000604E29464FF4806714432A46C0F88040E1 -:10297000A3F88C6148F2B826A3F88EC1A3F8905151 -:10298000B3F8880180B240F0F000A3F8880101EBB1 -:102990004100914B0131002540011C4604290344AC -:1029A000A3F804E0DF805A841A865A805A81DE81B7 -:1029B0005A82DA825A83DA83E9D1B4F888014FF077 -:1029C0000F0C874B4FF4704680B229464FF4604796 -:1029D0002A4640EA0C004FF4806EA4F88801B4F84F -:1029E000880180B240F47060A4F88801A3F88C617B -:1029F00048F2B826A3F88EC1A3F89051B3F8880125 -:102A000080B240F0F000A3F8880101EB4100744B64 -:102A10000131002540011C46042903449F80A3F88E -:102A200006E05A841A865A805A81DE815A82DA82F6 -:102A30005A83DA83E9D1B4F888014FF00F0C694B5F -:102A40004FF4704680B229464FF460472A4640EA68 -:102A50000C004FF4806EA4F88801B4F8880180B2AD -:102A600040F47060A4F88801A3F88C6148F2B8269D -:102A7000A3F88EC1A3F89051B3F8880180B240F05A -:102A8000F000A3F8880101EB4100564B013100250D -:102A900040011C46042903449F80A3F806E05A84A1 -:102AA0001A865A805A81DE815A82DA825A83DA8300 -:102AB000E9D1B4F888014FF00F0C4B4B4FF470473D -:102AC00080B229464FF460462A4640EA0C004FF493 -:102AD000806EA4F88801B4F8880180B240F4706078 -:102AE000A4F88801A3F88C7148F2B827A3F88EC126 -:102AF000A3F89051B3F8880180B240F0F000A3F839 -:102B0000880101EB4100384B013140011C4604298A -:102B100003449E80A3F806E05A841A865A805A819C -:102B2000DF815A82DA825A83DA83EAD1B4F88831B3 -:102B30000F27002241F201069BB245F6C05E114606 -:102B400043F226053B43A4F88831B4F888319BB2A0 -:102B500043F47063A4F888315001244B01320344DC -:102B6000042A99815981DF819E82A3F806E01980A9 -:102B700019829D81F0D100220F2741F2010645F60E -:102B8000C055114643F226045001194B013203444B -:102B9000042A99815981DF819E82DD801980198202 -:102BA0009C81F1D100220F2741F2010645F6C05564 -:102BB000114643F2260450010E4B01320344042A0D -:102BC00099815981DF819E82DD80198019829C81E3 -:102BD000F1D1F0BD00C00F4000C03D40000003FC3B -:102BE00000003E4000403E4000803E4000C01D408E -:102BF00000001E4000401E4038B5074B1C784CB109 -:102C0000064D55F8043F002BFBD09847631E13F088 -:102C1000FF04F6D138BD00BFA80D0020880D0020AC -:102C2000014B00221A707047B803002070B50F4E98 -:102C30000F4D761BB61018BF002405D0013455F88F -:102C4000043B9847A642F9D10A4E0B4D761B00F083 -:102C500063F8B61018BF002406D0013455F8043BC1 -:102C60009847A642F9D170BD70BD00BF48160060FC -:102C700048160060501600604816006070B4840763 -:102C800046D0541E002A41D0CDB2034602E0621E57 -:102C9000E4B3144603F8015B9A07F8D1032C2ED94C -:102CA000CDB245EA05250F2C45EA054519D903F1B2 -:102CB00010022646103E0F2E42F8105C42F80C5CC3 -:102CC00042F8085C42F8045C02F11002F2D8A4F168 -:102CD000100222F00F0204F00F041032032C1344F0 -:102CE0000DD91E462246043A032A46F8045BFAD858 -:102CF000221F22F003020432134404F003042CB117 -:102D0000C9B21C4403F8011BA342FBD170BC70473D -:102D100014460346C2E700BF5FF800F0E11500600B -:042D2000F8B500BF43 -:102D240000000042C8801F40B8821F400800000015 -:102D340000000042C4801F40B4821F400400000011 -:102D440000C0004224801F4014821F401000000075 -:102D540000C0004228801F4018821F40200000004D -:102D640000C000422C801F401C821F404000000015 -:102D740000C0004234801F4024821F400001000034 -:102D84000040004264811F4054831F40000400003F -:102D94000040004280811F4070831F4000000200F9 -:102DA400004000427C811F406C831F4000000100F2 -:102DB4000040004268811F4058831F400008000003 -:102DC400004000423C811F402C831F400100000052 -:102DD4000040004244811F4034831F40040000002F -:102DE4000040004240811F4030831F400200000029 -:102DF4000040004248811F4038831F400800000003 -:102E04000000004204811F40F4821F4000000400BF -:102E14000000004208811F40F8821F4000000800A3 -:102E24000000004218811F4008831F4000008000FA -:102E34000000004214811F4004831F400000400032 -:102E44000000004200811F40F0821F400000020089 -:102E540000000042FC801F40EC821F400000010083 -:102E64000000004224811F4014831F40000000041E -:102E74000000004228811F4018831F400000000802 -:102E8400000000421C811F400C831F400000000111 -:102E94000000004220811F4010831F4000000002F8 -:102EA40000000042EC801F40DC821F400010000044 -:102EB40000000042F0801F40E0821F40002000001C -:102EC4000000004234811F4024831F400000004062 -:102ED4000000004238811F4028831F40000000800A -:102EE4000080004294801F4084821F400000040040 -:102EF40000C0004290801F4080821F40000000807C -:102F040000800042A8801F4098821F40000080007B -:102F140000800042A4801F4094821F4000004000B3 -:102F2400004000426C811F405C831F400010000081 -:102F340000C0004230801F4020821F4080000000FB -:102F440000800042C8811F40B8831F4000800000F9 -:102F540000800042C4811F40B4831F400040000031 -:102F640000800042C0811F40B0831F400020000049 -:102F740000800042BC811F40AC831F400010000051 -:102F840000800042D0811F40C0831F400000020027 -:102F940000800042CC811F40BC831F400000010020 -:102FA4000001000068030020120000000006000079 -:102FB400000300200A000000000200002403002097 -:102FC4004300000000070000240300204300000029 -:102FD4000003000094030020000000000103090422 -:102FE4000C03002000000000020309047C030020FD -:102FF40000000000030309049803002000000000FF -:1030040000000000000000000000000004000000B8 -:103014000C000000090000000B0000000A00000082 -:103024000A060002020000400100000018035400D8 -:10303400650065006E007300790064007500690026 -:103044006E006F0009024300020100C0320904004F -:103054000001020201000524001001052401010100 -:10306400042402060524060001070582031000104B -:1030740009040100020A00000007050302400000E1 -:103084000705840240000000120100020200004013 -:10309400C0168304790201020301000016035500DF -:1030A4005300420020005300650072006900610073 -:1030B4006C000000040309040C030000000000007D -:1030C40000000000000000000000000000000000FC -:1030D4000029DE07007B9A170100000000000000B1 -:040000056000100087 -:00000001FF diff --git a/tools/test-rig-rpi.yaml b/tools/test-rig-rpi.yaml index 7078aad2..33588274 100644 --- a/tools/test-rig-rpi.yaml +++ b/tools/test-rig-rpi.yaml @@ -8,15 +8,27 @@ components: name: rpi ssh: odrv net: homenet - can0: main_canbus - uart0: /dev/serial/by-id/[not-yet-used] + components: + - type: uart + name: uart0 + port: /dev/ttyS0 + connected-to: main_uart + - type: can + name: can0 + interface: can0 + connected-to: odrive.can + # need to specify GPIOs explicitly for the generalpurpose type + - {type: gpio, num: 16} + - {type: gpio, num: 19} + - {type: gpio, num: 20} + - {type: gpio, num: 26} - - type: programmer - name: The Blue STLink/v2 - id: '\x53\x3f\x75\x06\x49\x3f\x49\x51\x44\x54\x19\x3f' +# - type: programmer +# name: The Blue STLink/v2 +# id: '\x53\x3f\x75\x06\x49\x3f\x49\x51\x44\x54\x19\x3f' - type: odrive - name: ODrive + name: odrive board-version: v3.6-58V serial-number: "20703595524B" brake-resistance: 0.47 @@ -40,15 +52,42 @@ components: max-voltage: 40 - type: encoder - name: real_encoder_0 - cpr: 8192 - max-rpm: 7000 - - - type: encoder - name: real_encoder_1 + name: real_encoder cpr: 8192 max-rpm: 7000 - type: teensy name: teensy - + + - {type: lpf, name: lpf0} + - {type: lpf, name: lpf1} + +connections: + - ['odrive.can', 'rpi.can0'] + - ['teensy.program', 'rpi.gpio26'] + - ['teensy.gpio11', 'rpi.uart0.tx'] + - ['teensy.gpio12', 'rpi.uart0.rx'] + - ['teensy.gpio10', 'odrive.gpio1'] + - ['teensy.gpio9', 'odrive.gpio2'] + - ['teensy.gpio8', 'odrive.gpio3'] + - ['teensy.gpio7', 'odrive.gpio4'] + - ['teensy.gpio14', 'odrive.gpio5'] + - ['teensy.gpio15', 'odrive.gpio6'] + - ['teensy.gpio16', 'odrive.gpio7'] + - ['teensy.gpio17', 'odrive.gpio8'] + - ['teensy.gpio4', 'rpi.gpio20'] + - ['teensy.gpio5', 'rpi.gpio19'] + - ['teensy.gpio23', 'odrive.encoder0.z'] + - ['teensy.gpio22', 'odrive.encoder0.a'] + - ['teensy.gpio21', 'odrive.encoder0.b'] + - ['teensy.gpio20', 'odrive.encoder1.z'] + - ['teensy.gpio19', 'odrive.encoder1.a'] + - ['teensy.gpio18', 'odrive.encoder1.b'] + - ['teensy.gpio0', 'real_encoder.z'] + - ['teensy.gpio1', 'real_encoder.a'] + - ['teensy.gpio2', 'real_encoder.b'] + - ['odrive.axis0', 'D5065-270KV_0'] + - ['D5065-270KV_0', 'real_encoder'] + - ['odrive.gpio3', 'lpf0'] + - ['odrive.gpio4', 'lpf1'] + - ['lpf0.en', 'lpf1.en', 'rpi.gpio16']