#include "syringefilled.h" StaticJsonDocument<200> SyringeFilled :: syringe_filled_json; //200 = RAM allocated to this document ISRStepper stepper(AccelStepper::DRIVER, STEP, DIR); SyringeFilled syringe_filled(stepper); //CONSTRUCTORS SyringeFilled :: SyringeFilled (MotorHardware_t& stepper): Motor(stepper) { set_exchange_throughput_uL_per_sec(1); set_exchange_volume_mL(1); set_remaining_volume_mL(1); set_push(true); set_name_syringe("BD_10mL"); set_screw_thread_mm(4); set_clockwise_equals_push(true); set_emergency(false); } //SET METHODS void SyringeFilled :: set_exchange_throughput_uL_per_sec(float exchange_throughput_uL_per_sec) { syringe_filled_json["exchange_throughput_uL_per_sec"] = exchange_throughput_uL_per_sec; } void SyringeFilled :: set_exchange_volume_mL(float exchange_volume_mL) { syringe_filled_json["exchange_volume_mL"] = exchange_volume_mL; } void SyringeFilled :: set_remaining_volume_mL(float remaining_volume_mL) { syringe_filled_json["remaining_volume_mL"] = remaining_volume_mL; } void SyringeFilled :: set_push(bool push) { syringe_filled_json["push"] = push; } void SyringeFilled :: set_name_syringe(String name_syringe){ syringe_filled_json["name_syringe"] = name_syringe; } void SyringeFilled :: set_screw_thread_mm(float screw_thread_mm) { syringe_filled_json["screw_thread_mm"] = screw_thread_mm; } void SyringeFilled :: set_clockwise_equals_push(bool clockwise_equals_push) { syringe_filled_json["clockwise_equals_push"] = clockwise_equals_push; } void SyringeFilled :: set_emergency(bool emergency) { syringe_filled_json["emergency"] = emergency; } //GET METHODS float SyringeFilled :: get_exchange_throughput_uL_per_sec() { return syringe_filled_json["exchange_throughput_uL_per_sec"].as<float>(); } float SyringeFilled :: get_exchange_volume_mL() { return syringe_filled_json["exchange_volume_mL"].as<float>(); } float SyringeFilled :: get_remaining_volume_mL() { return syringe_filled_json["remaining_volume_mL"].as<float>(); } bool SyringeFilled :: get_push() { return syringe_filled_json["push"].as<bool>(); } String SyringeFilled :: get_name_syringe() { return syringe_filled_json["name_syringe"].as<String>(); } float SyringeFilled :: get_screw_thread_mm() { return syringe_filled_json["screw_thread_mm"].as<float>(); } bool SyringeFilled :: get_clockwise_equals_push() { return syringe_filled_json["clockwise_equals_push"].as<float>(); } bool SyringeFilled :: get_emergency() { return syringe_filled_json["emergency"].as<bool>(); } const StaticJsonDocument<200>& SyringeFilled :: get_syringe_filled_data() { return syringe_filled_json; } //CONVERSIONS StaticJsonDocument<200> syringe_filled_json; //200 = RAM allocated to this document float SyringeFilled::volume_to_distance(float volume_mL) /*** -Argument : Volume in mL. -Return : The distance to cover associated in mm. -Action : / ***/ { float volume_mm3 = 1000*volume_mL; //mL->mm3 float piston_surface_mm2 = Syringe :: get_syringe_database()[syringe_filled_json["name_syringe"]]["internal_diameter"]; float distance_mm = volume_mm3/piston_surface_mm2; return distance_mm; } float SyringeFilled::distance_to_volume(float distance_mm) /*** -Argument : distance in mm. -Return : The volume associated in mL. -Action : / ***/ { float piston_surface_mm2 = Syringe :: get_syringe_database()[syringe_filled_json["name_syringe"]]["internal_diameter"]; float volume_mm3 = distance_mm*piston_surface_mm2; return volume_mm3; } //MOVEMENTS void SyringeFilled :: exchange() /*** -Argument : / (We're using informations stored in the class itself) -Return : / -Action : Move the syringe filled to deliver or recover the volume expected ***/ { //Conversions of volumes float remaining_volume_mm3 = get_remaining_volume_mL()*1000; float exchange_volume_mm3 = get_exchange_volume_mL()*1000; //Find the section float radius = Syringe :: get_syringe_database()[syringe_filled_json["name_syringe"]]["internal_diameter_mm"]; float section_mm2 = M_PI*radius*radius; set_speed_mm_per_sec(get_exchange_throughput_uL_per_sec()/section_mm2); if (where_step() == 0) //If we are putting the syringe for the first time { move_to_mm(syringe_pump_length_mm - remaining_volume_mm3/section_mm2); } else { float initial_position_mm = syringe_pump_length_mm - remaining_volume_mm3/section_mm2; if (get_push()) //If we want to deliver some liquid { move_to_mm(initial_position_mm + exchange_volume_mm3/section_mm2); } else //If we want to recover some liquid { move_to_mm(initial_position_mm - exchange_volume_mm3/section_mm2); } } } void SyringeFilled :: go_to_zero() /*** -Argument : / (We're using informations stored in the class itself) -Return : / -Action : Move the syringe filled to deliver or recover the volume expected ***/ { Serial.printf("ok1"); if (get_emergency()) { Serial.printf("ok2"); return; } else { Serial.printf("ok3"); set_speed_mm_per_sec(-1); Serial.printf("ok4"); reset_position(); Serial.printf("ok5"); move_to_mm(-200); Serial.printf("ok6"); } } //LIMIT SWITCH void SyringeFilled::manage_emergency (bool pressed, bool at_zero) /*** -Argument : two boolean to know the position of the limit switch and if we are a the zero -Return : / -Action : Manage different emergency cases (move the pump if necessary) ***/ { if (pressed) //if the limit switch is pressed { set_emergency(true); if (at_zero) //if we are at te initialisation place { run_from_emergency(); } else { Serial.printf("EMERGENCY: Pressed by someone\n"); } } else { set_emergency(false); Serial.printf("EMERGENCY: released\n"); stay_here(); reset_position(); //zero is here again Serial.printf("ZERO: reset\n"); } } void SyringeFilled::run_from_emergency() /*** -Argument : / -Return : / -Action : Move the pump slowly until the limit switch is released ***/ { if (get_emergency()) { Serial.printf("EMERGENCY: running away slowly\n"); set_speed_mm_per_sec(-1); reset_position(); move_to_mm(200); } } //CONFIGURATION bool SyringeFilled :: check_configuration() /*** -Argument : / -Return : A boolean true(everything is fine), false(at least one attribut is'nt correct) -Action : Check if the values are correct. ***/ { if (Syringe :: get_syringe_database()[syringe_filled_json["name_syringe"]]["internal_diameter"] <= 0) return false; if (get_exchange_volume_mL() < 0) return false; if (get_remaining_volume_mL() <= 0) return false; if (get_exchange_throughput_uL_per_sec() <= 0) return false; return true; } void SyringeFilled :: show_configuration() /*** -Argument : / -Return : / -Action : Displays syringe filled attributes ***/ { //Motor::show_configuration(); auto step = where_step(); Serial.printf("# push clockwise: %s\n" //"# diameter: %g mm\n" //"# capacity: %g uL\n" "# rate: %g uL/s = %g mm/s\n" "# volume remaining: %g uL (target)\n" "# direction: %s\n" "# emergency: %d\n" "# current position: %g mm\n", get_clockwise_equals_push()? "yes": "no", //Syringe :: get_syringe_database()[syringe_filled_json["name_syringe"]]["internal_diameter"], //Syringe :: get_syringe_database()[syringe_filled_json["name_syringe"]]["total_volume_mL"], get_exchange_throughput_uL_per_sec(), volume_to_distance(get_exchange_throughput_uL_per_sec()), get_remaining_volume_mL(), get_push()? "infuse": "withdraw", get_emergency(), step_to_mm(step)); } //Example : File f = ({ InterruptLock lock; filesystem->open(filename, "w"); }); and the f becomes the argument output_stream //useful in web.cpp via a button to save data void SyringeFilled :: write_Json (Stream& output_stream) //file_name sera le nom du fichier Json, doc sera la structure Json qu'on veut transformer en fichier { /*** -Argument : output_stream (= serial or a file) -Return : / -Action : Save the Json structure in a file (convert it to text) ***/ InterruptLock lock; //useful thanks to its constructor (so a is not visible in the code) serializeJson(syringe_filled_json, output_stream); } //useful in setup of pousse-seringue.cpp(to check at the begining what has already been saved) and web.cpp via a button to recover data void SyringeFilled :: read_Json (Stream& input_stream) //file_name sera le nom du fichier Json, doc sera la structure Json qu'on veut transformer en fichier { /*** -Argument : input_stream (= serial or a file) -Return : / -Action : Check if a Json Document alredy exist or not ***/ InterruptLock lock; //useful thanks to its constructor (so a is not visible in the code) deserializeJson(syringe_filled_json, input_stream); }