|
Виж темите без отговор | Виж активните теми
Дата и час: Вто Юли 28, 2026 12:42 am
| Автор |
Съобщение |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: RTOSes
Относно секюритата ще пасувам, но ще опитам да споделя идеи за другата част от проблеми. За да имя повече яснота ще опитам както теб да дам малко пояснения. Значи софтуера го разглеждам като изграден от две части - преизползваеми компоненти (кажи ги "библиотеки") и "интеграция", т.е. конкретно приложение, проект - нещото което навръзва викането на компонентите и изкарва елф-а. Теорията говори за термини "инверсия на контрол", както и за "dependency injection", но още тук да уточня че ще говоря за нещо малко по-изместено (разширено или недонаправено, поколенията ще решат). Едно важно пояснение е че прилагането на тези методи води до "изплуване" (bubble out) на спецификите (конфигурациите, проект-специфичните неща) към най-горното ниво - викат му "dependency injector". Компонентите не ги разделяме на стекове, протоколи, драйвери или такива неща и ще кажа защо - гледаме на тях като на "алгоритми", т.е. обработки които са тотално специфични, не съдържат данни (получават ги отвън), не включват в себе си никаква форма на зависимост от други алгоритми (компоненти). Туй му викат "single responsibility" принцип. Много често ни се налага да правим протоколи от типа "нещо over нещо". Примерно някакъв legacy протокол да мине върху нов транспорт, или да се закачи директно към друг компонент като функционално викане. А според идеологията за която говоря решението да направим "виртуален UART" който да закачи процес А с процес Б не е правилното решение. Другата важна черта е че при развоя (на компонентите) гоним идеята да използваме pattern-и които са преизползваеми и могат да се приложат както за драйвер, така и за протокол, така и за стек и т.н. Това е така защото компонентите са алгоритмични - сериализатор на някакъв протокол (от типа дай ми буфер, дай ми какво ще прави пакета и аз ще ти напълня буфера с подходящия пакет). Ако слагаме класификация че някакъв компонент е "драйвер" това идва да покаже че в него има нещо специфично, уникално за нивото "драйвери". В другите идеологии това е прието и си е нормално нещо - специфични интерфейси, начини за интегриране, достъпни ресурси и каквото и да е там, което прави "драйвера" различен от "стека". Това се стремим да го избегнем. Как постигаме тотално изолиране (махане) на зависимостите? Пример - протокол http който целим да ползваме през различни протоколи. Тук е първото важно нещо - single responsibility диктува че към момента на писане на http протокол библиотеката (сериализатор) НИ Е ЗАБРАНЕНО да питаме, искаме, търсим или предполагаме какъв транспорт ще се ползва. Т.е. нямаме достъп дори до абстракна дефиниция на транспортен клас (интерфейс) - с две думи ако някой сложи "transport.h" или нещо подобно в папката със сорсовете на http библиотеката гори. Това води до следното - тоя дето би "изгорял" е лишен от какъвто и да е прототип на функция/интерфейс с който да изпрати подготвения от него пакет. Натъртват на ИЗПРАТИ подготвения от него пакет. А това е така понеже като са му давали задачата изрично е казано - правиш функции за ПОДГОТВЯНЕ/АНАЛИЗИРАНЕ на http пакети и НИЩО ДРУГО. Та значи неговите функции приемат формата на result func(buf*, int a, bool b). Това което прави той е да отвори RFC-то за http (и да яде шамари ако посегне към RFC за TCP или даташит на микроконтролер, или документ за posix, или хедъри на lwip). Само RFC-то (и C/C++ стандарта) са му достъпни. Поставен в тази ситуация той е "принуден" да напише само http и да имплементира алгоритмите от RFC-то. Разбира се, на сбирките реве че не му казват повече за останалата част на системата и казва "знаеш ли колко хубаво ще стане ако ми дадете един transport.h и аз ще извикам функциите". Не, няма да ги получи защото: - тази информация ще му "помогне" само за да вкара вътре зависимости от тези документи/стандарти или дори конкретни имплементации - ако вкара викането вътре ще обвърже системата да пази съвместимост и да държи transport.h в даден вид - по всяка вероятност ще повика функциите вътре в неговите - т.е. ще направи две неща - да подготви пакета И ОСВЕН това да извика изпълнението на функцията за транспорта - написано така е очевидно че това са две що-годе отделни неща и има резон да не се обединяват Това води до няколко бонуса: - дали после тия пакети ще се пращат по transport.h, дали направо ще викат на стм32 апи-то за сериен, дали на тива за spi, дали на posix нещо няма никакво значение - нито един от хедърите на тия транспорти не е влязъл в сорса на http - за тест е елементарно да подам буферче, да получа попълненото и да го сравня с тестов вектор - никакви мок-ове, dummy-та и тем подобни - ако се смени transport.h като версия/API на http "парсерa" му е през ... - това че се е сменил tansport.h по никакъв начин не изисква да пускам тест на http - няма връзка между тях - ако искам да ползвам динамично алоциран буфер за аргумента на http ще си извикам malloc-а отвън и ще подам буфера, ако ми кефне да ползва локално масивче в стека пак мога, ако искам да ползвам глобална променлива нямам проблем, ако искам да ползвам област в някоя бърза памет също съм ОК - това не може да стане лесно ако бяхме оставили web дизайнера да алоцира вътре в http функциите. - контекстът на отделните компоненти се изчиства и минимизира - не е неоходимо компонентът http да има номер на tcp порт, url на сървър и тем подобни. Това си е висша форма на капсулиране без каквито и да е техники или поддръжка от компилатора В конкретния проект (устройство X) искаме да позлваме http по tcp, значи слагаме двата компонента, правим отделни структури с конфигурации за двата, ако много искаме правим горно ниво структура съдържаща двете отделни структури, по-точно конфигурационна и инстанционна на всеки компонент. На мен (от гледна точка на писач на някой компоненти или използвач в други устройства "Y" ми е през ... дали писача на X ще ги завърти така или иначе - нито го ограничавам да го направи, нито го карам да го прави. Ако за клиент Z е неоходимо да изкараме "а-ла-ардуино" упростено API е лесно - взимаме си компонентите, правим по-голямата структура с отделните малките, слагаме фунцкии които той да вика, а те да накачат една след друга нивата и сме в джаза. Пак, нито X, нито Y е "слязло" на ниво ардуино щото имало такъв клиент. Тези подходи са си много принципни и много чисти - в момента в който някой се зачуди как да направи нещо трябва да се замисли дали спазва няколко елементарни условия - споменатото single responsibility, функционални библиотеки от "чисти" функции ("pure functions") - такива които работят само с аргументите си и няма странични ефекти (върху глобални данни и скрито свързани други такива). Неприятното е че този подход е по-различен и изисква пренастройване на мисленето. Не е проблем да се използва съвместно с "legacy" код - т.е. не изисква всичко да е написано така в един проект. Другото е за споменатато "унифициране" на http и ftp - трудно е да стане такова нещо. Има някаква логика различни транспорти да се унифицират, но различните неща са си различни - евентуално може да съдържат малки части, които се дублират - но това просто значи че тези части трябва да излязат извън тях и да си останат само специфичните. Тия проблеми с "унифициране" на различните неща са били една от движещите сили да се отиде на инверсията на контрол. Пак теоретично казано, макар да не съм нещо повече от заинтересован читател на "теорията" по темата) е да се предпочита "композиция" вместо "наследяване". Сигурно не е ясно за какво говоря, затова пак ще цъкна един линк към елементарен код, който идва да покаже красотата на идеята: http://www.eclipse.org/paho/clients/c/embedded/ |  |  |  | Код: MQTTPacket_connectData data = MQTTPacket_connectData_initializer; int rc = 0; char buf[200]; MQTTString topicString = MQTTString_initializer; char* payload = "mypayload"; int payloadlen = strlen(payload);int buflen = sizeof(buf);
data.clientID.cstring = "me"; data.keepAliveInterval = 20; data.cleansession = 1; len = MQTTSerialize_connect(buf, buflen, &data); /* 1 */
topicString.cstring = "mytopic"; len += MQTTSerialize_publish(buf + len, buflen - len, 0, 0, 0, 0, topicString, payload, payloadlen); /* 2 */
len += MQTTSerialize_disconnect(buf + len, buflen - len); /* 3 */
rc = Socket_new("127.0.0.1", 1883, &mysock); rc = write(mysock, buf, len); rc = close(mysock);
|  |  |  |  |
Edit: да допълня по две споменатите неща: - спецификите (конфигурации, връзки) "изплуват" най-отгоре - контрола е инвертиран и изисква пречупване на мисленето Тия неща са си недостатъци и разумни хора са мислили по въпрост - викат "functional reactive programming" - FRP, или просто reactive. Там използват по-напреднали техники на езиците за да опишат по-ясно тези вериги от връзки, без да им се налага да "обръщат" контрола. Т.е. самите компилатори и рънтайми изпълняват кода "обърнато" а в сорса нещата си вървят в що-годе логичен ред. За C++ има едно майкрософтско изчадие - RxCPP - https://github.com/Reactive-Extensions/RxCpp. То е аналогия на RxJava, RxNet, и много други братчета които изпълняват този подход (реактивния). Обръщам внимание на RxCPP-то защото ми е най-четимо и изглежда да е най-близо до пускане на ембедед таргети (заради gcc/clang). Логиката на описанието там е не да се вика някой и да се работи с резултата от него, ами да се предаде резулата от нашата работа (например за http примера - получения пакет) към следващия. Образуват се такива насочени графове които показват (описват) реакцията на системата от някакъв вход до някакъв изход. Описанието изглежда близко като посока до това което е в стандартния (не-инвертиран контрол) и затова се смята че е по-разбираемо - е, за мен не е толкова ясно но то всеки който е чел haskell, ocaml и сие знае за какво говоря.
|
| Сря Май 17, 2017 2:13 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: RTOSes
gicho, това твоето не ми помага особено...
Значи в програмирането има различни концепции, но винаги има някакви нива на абстракции. Разликите са кой къде слага чертата и по какви причини. При мен нивата на абстракция са драйвер, стек, протоколи, нива... Най-простото е драйвер, щом има джелязо трябва да има драйвер. Може виртуален драйвер без джелязо, но джелязо без драйвер не. Самото джелязо може да е от най-различен характер, но драйверът му винаги има унифициран интерфейс. Демек драйверите правят различните джелеза да изглеждат почти еднакво за софтуера. И в много от случаите софтуерът може изобщо да не знае или да не иска да знае с какво джелязо си има работа, защото всичко което прави го прави с драйвер, а те всички драйвери имат еднакъв интерфейс. Следващото ниво на абстракция е стек. Има различни типове стекове комуникационни, GUI и т.н. Общото между тях е, че спрямо драйверите вдигат нивото на интерфейса и го специализират. Демек комуникационните стекове примерно ти позволяват да работиш на ниво сокет, графичните стекове ти позволяват да работиш на ниво GUI, примерно да изпраскаш един джам. И драйверите и стековете са вид библиотеки, но не какви да е библиотеки, а библиотеки със строго специфициранo API. API-то обаче не се свежда само до формат на данните а в ключва и алгоритми. Примерно сокетът се създава после connect/bind/accept и т.н.
Сега, когато се ползва даден интерфейс обвързването е нещо съвсем нормално, но се обвързваш само със съответния ТИП интерфейс. В случая с HTTP е нормално и даже НЕИЗБЕЖНО да се обвържеш с комуникационен стек. Не с конкретен, а по пинцип с комуникационни стекове. Иначе това дето го правиш става ебана, но недоебана работа и трябва отвън да му слугуваш. Това се опитвам да избегна. Аз не искам изобщо да знам дали ползвам http, а още по-малко пък да му попълвам структури. Ами ако сървъра ме редиректне кво правим? Да търся да попълвам нови структури щото новия URL може изобщо да не е достъпен със стария комуникационен интерфейс. И това да го правя на всяко място дето имам някаква комуникация - НЕ, МЕРСИ!
Правилото е когато се ползва нещо, то да е максимално проЗто и да изисква МИНИМУМ познания. Аз се стремя да ползвам това правило навсякъде. Примерно като ползвам RTOS аз никъде не му бая и нито пускам, нито инициализирам кърнели, драйвери или стекове. Те са там и си се спасяват и мен не ме интересуват до момента в който не ми потрябат. Ако ми потрябва да кажем драйвер, просто го ползвам, не е задължително даже да знам как работи. Същото и със стековете и протоколите. Щом съм стигнал до някаква комуникация значи имам да пращам или получавам данни. Аз си гледам данните, не ме интересува комуникацията. За мен важното е да работи, т.е. да знам че данните се трансферират успешно или не. А пък дали се е ползвало http/ftp какви протоколи, какви интерефейси - изобщо не ми дреме. А и да ми дремеше е все тая, защото аз НЕ знам предварително какво ще се ползва. Това дето ти си чертаеш вериги и графове и описваш пътища за мен е абсолютно безсмислено. Аз не си играя да фърлям боб и да следя кое от къде може да мине. Интересувам се само от по-общи неща като това дали минава, за какво време, да го спра ако не ме кефи и т.н.
|
| Сря Май 17, 2017 4:45 pm |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: RTOSes
Сега, познавам идеите за които говориш - по-скоро като потребител, а не като писач на ртос. Сблъсквал съм се с някой от проблемите, чел съм за заобиколките - за мен е идеологично грешно и неприемливо да се прилагат такива концепции при толкова висок риск от проблеми. Твоята гледна точка е по-различна и мисля че я схващам - за теб е важно да постигнеш продукт (в смисъла на решение, не говоря за комерсиалния аспект). Този продукт трябва да намери потребителите си - т.е. да е лесен за ползване. В голяма степен това означава интерфейса му да отговаря на очакванията на потребителите - хубав, лош, ефективен или не трябва да е така. Разлики обаче може да има в това как е изградено вътрешно това нещо. Не ти говоря да чертаеш графове - имам предвид че описването на взаимодействието на компонентите в софтуера реално изгражда един граф (тъй де, множество) и той е насочен някак си - от "входа" към "изхода" - от аргументите към върната стойност. Естествено че се пише на нормален език за програмиране - представи си call stack-а в даден таск който е за да се свърши някаква работа - тази последователност от накачени стъпки-функции показват как от някакъв вход (аргументи от командния ред, постване в мейлбокс, приемане на пакет) се преминава през обработките и се стига до изходен резултата - отпечатано в stdout, постване в друг мейлбокс, пращане на пакет обратно по интерфейс. Но това си е нещо теоретично и не виждам смисъл да го диплим изобщо. И преди сме говорили за абстракции и там има много тъмни сили. Прекалено субективно е, липсва логика която да те "принуди" да го направиш правилно, в смисъл ефективно по някакъв реален критерий. Сигурно има нива и точки където може да се гледа по този начин. Но със сигурност натрупаната инерция в съсловието води до откровени безсмислици. Примерно опит да се приравни SPI и I2C и UART и Ethernet. Те си има определени разлики, и да приемем че имат и общи характеристики. Най-малкото трябва да се отделят два отделни интерфейса - като има нещо общо (примерно send и receive) те да останат като някакъв вид стрийм или транспорт или нещо такова. Но конфигурирането, контрола на специалните сигнали (flow control, chip select, start/stop/ack/nack) са специфични. Ако дадена "верига" в софтуера се интересува само от "send" и "receive" то тя може да работи с общ интерфейс, имплементиран в специфичние (конкретен) клас на дадения "драйвер". Аз съм против това да се опитва останалото - конфигуриране и всичко дето е на IOCTL да се унифицира. Какво е това IOCTL? Как така ще се съгласяваме да има в namespace-а на UART термина "chip select", или в този на SPI да имаме "cts/rts" примерно? Сега, дори send/receive е донякъде некоректно - то може и да изглеждат по един и същ начин (прототип на функцията) ама уарта ще да има примерно 64 байта буфер вътрешно, spi-a и той да кажем толкова, ама етернета може да има примерно 32К. Реакцията на различните имплементации е различна - дали като време за работа, дали като други ефекти (стек, необходими аргументи като дма конфигуриране и тем подобни). Както и да е, тезата ми е насочена към това дали може да приложи друга концепция: - която да няма нужда от привеждането на различните "драйвери" към псевдо общ формат - да позволи премахването на зависимостите между компонентите и извеждането им като "връзки" от типа "композиция" (а не наследяване) на по-горно ниво - да не натоварва повече системата в смисъла на ресурси - да даде повече "видимост" на компилатора за да може той да оптимизира и проверява по-ефективно и съответно да намалим или елиминираме нуждата от рънтайм проверки - да позволи произволен модел на управление на паметта - вече споменах че за мен (нас) е от изключително значение да избягваме динамична памет - прилагане на pattern който налага динамична памет е табу Както ти спомена чрез техники в C++ (като цяло в компилатора и/или рънтайма на езика) можеш да направиш ефективно управление на динамичната памет - не знам дали е това което описа е RAII - https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization. Това съвсем може да се реши с боклукчии, но май нямат много приложение в ембедед. Та за момента мога да кажа че има такива решения и затова не мога да приема тези "така се прави" и "няма друг начин". Отворен съм за дискусия по определени точки както вече спомена - ще прочета пак какво си описал и ще отговоря. Ако ти е интересно да обсъждаме де. Следващото ниво (функционалното програмиране - Haskell, ocaml) ми е тъмна индия и ако там някой може да помага ще съм благодарен. Но натам отиват нещата - много е елегантно да навържеш дребни, специализирани тулчета (grep, awk, tail, xargs) и един ред да постигнеш резултат.
|
| Сря Май 17, 2017 8:55 pm |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: RTOSes
В смисъл? Предполагам затваряш тоя сокет и отваряш нов? Всъщност - не - според стандарта предполагам трябва според URL-а да резолвнеш какво да правиш, т.е. накъде да отидеш. Не съм запознат в детайли, но не мисля че според http-то трябва да се минава само през сокети. Имам предвид че префикса може да каже tcp://, може в един момент от времето да каже serial:// (хипотетично). Дори и да има някаква референция към сокети едва ли пише "BSD SOCKET API", което е достатъчно да не искаме да include-ваме определен хедър и да се обвързваме с него. Както казах, постави се в ситуацията в която имаш едно или няколко RFC-та които трябва да имплементираш. Вътре намираш код за отговор при който трябва да редиректнеш. Значи имплементираш тази част която е там. Това на изисква да ровиш по сокети - ти генерираш сигнал (евент) с който съобщаваш че това трябва да се случи. Питаш клиент/шеф/колега - "Какво ще е TCP API-то в тоя новия проект" и ти казват - - "Намерили сме един нов стек дето е страшен- яката работа, ама още не е дошла документацията." - "Ама поне синхронно или асинхронно е?" - "Амии, тия дни ще пратят сорсове и ще видим, ама ти гледай да си готов дотогава че ще отървеш Майорката - нали ти дадохме документацията за твоя протокол?" При теб имаш "лукса" да можеш да портираш твоята система (ртос/стекове) за таргетите с които работиш. При мен е различно - някой харесва нов чип, ма armv5, кортекс, мипс, x86 или друга (NDA) дивотия е, и казва "- Дерзайте! Продавачът каза че имало HAL за всичката периферия и да не ми се оправдавате че бил нов чипа - ей ви компилатор, ей ви HAL-а и да видя как сте подкарали нашите функционалности върху тоя хардуер за нула време!" В такава ситуация е много полезно да не ми се налага да обвивам недоклатения HAL на stm примерно към някакви измислени абстракции. Не че не може, ама няма нужда - в най-горното ниво дето съм викал на mips примерно "mips_specific_blabla_uart_bla(bla,bla, buffer)" във файл main.c в папка "mips" се променя на arm_specific_stm_Bla(buffer, bla,bla, bla). Това е опростено разбира се, но показва логиката. Едит: всъщност го гледаме твърде теоретично - моята теза е че колкото и да "абстрахираме" драйвера за SPI-а никога няма да можем да постигнем заветната цел - някой web дизайнер дето е чувал само за файлово API да може да подкара истинска SPI комуникация. Не че няма да разчете че може да извика write() за хендъл на "/dev/spi0", ами че докато не му стане ясно какво е това SPI няма да има завършена задача. Баси как го увъртях - искам да каже че без поне повърхностно познаване на специфичните неща по даден интерфейс работа не се върши. По спомен от ранните ми сблъсъци с embedded линукса имаше постановки тогава точно тия интерфейси - uart, i2c, spi да се представят така абстрактно, като файлови нодове. Нещо обаче напоследък гледам че са си съвсем специфични API-та. Отделно за серийния и там има разните termios и подобни специализирани. Без да съм много напреднал си правя изводи по тия факти. Между другото, като тема за размисъл - според мен популярния подход за блокиращ с таймаут read/write е неефективен. За мен много по-смислен е write() / RegisterOnReadCallback(fn)
|
| Сря Май 17, 2017 9:52 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: RTOSes
Не знам какво разбираш под "правилно", явно разбираме различни неща. За мен правилно означава кодът който пиша да е супер лесен за ползване. Това, както и концепциите не съм ги измислил аз разбира се. Примерно под лайнукс вероятно си чувал и знаеш, че всичко е файл. Да, всичко е файл, дори неща, които на пръв поглед може да ти изглеждат безсмислено като файл. Но са факт. И благодарение на тоя факт с един инструмент може да свършиш много и най-различни неща. Примерно с grep мога да ровя навсякъде и за всичко. Интересува ли го греп къде ровя? Не! Както и конзолата, имаш ли достъп до конзола може да правиш всичко, буквално всичко. Итересува ли я конзолата за какво я ползваш и как я ползваш? И дали я ползваш правилно или разумно? Може ли да доведе до безсмислици, да може, но какво от това? Няма вариант и абстракция, която да спре един идиот да прави безсмилици. Има инструменти и концепции, обаче, които в подходящи ръце могат да правят всичко, буквално всичко. Номерът е това, което е общо да може да се ползва навсякъде. Винаги има уникални или специфични неща. За тя се налага да има специфични операции. Но ще се изненадаш колко много са общите неща и колко интерфейсите са взаимнозаменяеми. Няма никакво значение дали си против или не. Конфигурирането като процес е универсално, в противен случай не би могъл да работиш с неизвестен драйвер. Ще умреш още на конфигурирането. IOCTL-те също до голяма степен са си универсални. Примерно RESET се вика на всички драйвери. Разбира се има и къстъм контроли (когато се налага). Специално SPI и UART са съвсем заменяеми. И е нещо, което се налага и даже ползваме, тъй като нашите общи любимци от ST са решили, че SPI не може да е 9-битов. За сметка на това пък USART-a им работи прекрасно в 9-битов SPI режим. Много от малките дисплеи ползват 9 битови трансфери и са SPI, но уви не можеш да ги вържеш към SPI-a и трябва да ползваш USART. Да не навлизам в детайли за CS, RTS/CTS и т.н. сигурно ще има ситуации в които двата драйвера няма да са взаимнозаменяеми. Но за горната ситуация, както и много други при които просто не ми достигат единия или другия тип интерфейси си ги заменям, стига пинове да паснат и да няма някакви хардуерни изисквания. За софтуера те уверявам че няма такива и нямам грижи нито с GUI когато трябва да ползва един или друг драйвер, нито файловите системи се сърдят че вместо едното им давам другото. Те всъщност не ги интересува какво им даваш. Мда... точно табу е. Действително чисто Ц плюс динамична памет са взривоопасна комбинация. Но тоя проблем отдавна е решен като минеш на ++. Няма никакви проблеми, нито лийкове, нито някакви отвявания, замисляния и тем подобни. Така е, но това е благодарение на абстракциите за които ти говоря. Функционалното програмиране няма абсолютно никаква заслуга и изобщо връзка.
|
| Сря Май 17, 2017 10:38 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: RTOSes
Значи редиректването може да е към същия или друг сървър и естествено ако е към друг трябва да отвориш нов сокет. Като по принцип нямаш гаранция, че ще се ползва същия мрежов интерфейс. При големите ОС обикновено стека избира или по-точно казано рутира заявката. При нас обаче това се ползва много често и няма възможност за автоматично рутиране, тъй като или не се знае какво е достъпно в дадената мрежа или се знае, ама маршрута се определя на друг принцип. Затова сме си измислили начин да си указваме вътре в URL-то и интерфейса. Това не е стандарно, демек не е готино но нямаме избор. Примерно обикновено ползваме SIM карти с по 2 APN-a. Как и за какво ще ползват тия APN-и не го решаваме ние. Клиента плаща и си решава за това ще ползвам тоя APN или ще ползвам етернет или wifi... Зависи от пари и не само себестойност, щото не че го ползваме, ама имаме възможност да ограничаваме някои неща като набием заявките за дадени операции към наш сървър. Ако искаме ги обслужваме, ако не искаме не ги обслужваме, ако искаме можем да ги пренасочим някъде, ама за целта можем да поискаме заплащане  Въпросът е, че при пренасочването често се сменя не само сървъра ами и интерфейса... И тъй като тая магария с пренасочванията си е заложена в http протокола, то най-нормалното нещо е той да си я прави, а не функцията да излиза и ти да трябва да правиш пренасочвания. Това е все едно някой от туловете като grep, awk и т.н. да излизат по средата на работа и да трябва да ги пускаш с други парамтри.... Нали разбираш, че това тотално би осрало пейзажа...
|
| Сря Май 17, 2017 11:10 pm |
|
 |
|
TheWizard
Ранг: Форумен бог
Регистриран на: Сря Апр 27, 2005 12:48 pm Мнения: 6094
|
 Re: RTOSes
и толкова мноо приказки за някакъв си Лайнукс...
_________________ main[-1u]={1};
|
| Чет Май 18, 2017 7:03 am |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: RTOSes
Напротив, даже си е много ефективен. Проблемът е, че задължително изисква кърнел, докато решението с калбак работи и с ОС и без ОС. Затова второто се предпочита в по-универсални библиотеки. Аз нямам грижи със самите калбаци стига да са направени като хората. Често давам за пример LwIP - може да го ползваш както си искаш. Всъщност проблемът който имам с някои от секюрити библиотечки не е в това че ползват калбаци, а че им липсва възможност за таймоут. Калбака ме спасява дотоколкова, че не ме блокират и мога да си правя нещо други докато чакам. Включително и да си проверя часовника. Но като видя че времето е изтекло трябва да имам възможност и да канселирам операцията и да приключа. Това е нещо, което не видях как може да стане, а без него - кофти. може и за бозата да си говорим ако искаш 
|
| Чет Май 18, 2017 10:17 am |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: RTOSes
Амиии - то това си е доста близка постановка при асинхронното викане. Идеята е следната - някъде се случва нещо (за цвят, да кажем прекъсване на цифров вход) и ти трябва да поискаш нещо - да кажем пращане на пакет по някакъв интерфейс. Имаш асинхронна библиотека която ти дава метод "sendPacket()" примерно и има аргумент колбек да те извести кога е "изпратен" (да приемем че това е rs485 и искаш да знаеш кое е реално излязъл по бъса (transmit ready) или пък е CAN и искаш да знаеш кога е потвърден от друг нод по бъса). В твоята логика искаш да добавиш че ако до 1000мс пакета не е изпратен (stall, липсва друг нод) да направиш нещо - примерно да светнеш лампа. Сега, тука се виждат няколко отделни неща: - имаш едно парче код в който описваш какво да се прави при успешно потвърждение - това е callback-а за "изпратен" - имаш друго парче код - светването на лампа (примерно викане на функция gpio_write(RED_LED, ON) ) - имаш и трето парче код - това което прави повикването на sendPacket() Понеже идентифицирахме двете отделни, независими парчета код - myOnSent() и myOnTimeoutError() можем да си ги опишем и те изглеждат доста семпли и преизползваеми. В "класическия" подход след ретърна от synchronousWrite() ще имаш едно if-че което ще раздели нещата според ретърн кода - if (OK == res) {...} else if (TIMEOUT == res) {...} else.... Тоя код (pattern) с if за res почва да се повтаря често из кода, но това е малкият проблем. Истинската мъка е че докато чакаш тоя таймаут (примерно 1000мс) този тред в който си повикал synchronousWrite() е мъртъв - той не може да реагира на други заявки. Т.е. той трябва да е посветен на тази заявка. Сега, в нарочно подбрания пример даже съвсем не става - щото казахме че е било прекъсване - значи от прекъсването будим тред който да свърши работата. Ако се развие постановката можеш да видиш че цялата работа в тоя случай може да се извърти само през прекъсванията - оригиналното за входа, прекъсването за приключило изпращане на уарта и таймерско прекъсване. Количество код? Нужда от ОС? Размер на процесорчето дето ще го свърши? Нещо специфично да има в написания от нас код дето реагира на бутона и праща пакет? Уарт драйвера изобщо не е чувал дали и какъв е таймера, както и няма нужда от аргумент uint32_t ulTimeoutMs. Нямаме нужда и от неща като event групи / waitformultipleevents() каквито би трябвало да осигурим ако искаме да реагираме две събития (таймаут и завършване). Сега, да не кажеш че гледам опростено - същия код който сме написали за 8051 варианта няма никакъв проблем да се закачи към по-сложна система - в смисъл такъв в ОС, с общ модул за таймаут (понеже имаме само един таймер а искаме 1000 софтуерни). Реално кода който сме написали е във "функционален" стил - написали сме три функции: - Do() - тази която слагаме в прекъсването на бутона - или в треда дето реагира на веригата от 14 пост-а в мейлбокса в "сложната система" - OnError() - която избира цвят за лампата - OnSent() - ся, това е относително - в идеята с граф-овете това е излишно, но за разкош Тия трите нямат нищо ОС или "без-ОС" специфично В тази опростена постановка има един проблем - възможно е времево състезание между колбека и таймаута (тъй де, двата колбека) - могат да дойдат близо един до друг, че даже и да се изпопрекъснат един друг. За целта може да се приложи приоритизиране и state на заявката, но като цяло решенията са много по-леки от шедюлър, event group и подобни. Реално точно тези проблеми решава pattern-а за активните обекти, но него няма да го намесваме. Тъй де, зачехнах това със синхронно vs асинхронно защото спомена за особености при интегрирането на асинхронното. За да стане лесно трябва да се използват неговите идеи и силни страни. Опита да се "абстрахира" и докара до емулация на синхронно е само един от подходите. А всъщност има и нещо друго с колбеците - номерът е че колбека изисква две неща - метод/функция и контекст - за да може метода да получи данните, които са му нужни да свърши работата си. Затова масовия вариант е да се задава с два аргумента - адрес на функция и някакъв контекст в смисъла на "Me", "this" и т.н. На C++ това е улеснено. На истински функционалните езици (а, и а новите версии на c++ които го поддържат) се позлват "closure"-и или анонимни функции. Мисля че от 11-ката на c++ (гцц 4.8 мисля) анонимните функции са работоспособни. Хитрото там е че предаването на тоя контекст става лесно - със средствата на езика се задава "capture" списък и променливите, които ти трябва оттатък, след колбека, се запомнят автоматично. Отделно могат да са множество, не е нужно да ги организираш в структури, или да подаваш пойнтъри към големи структури/класове в които 90% от данните са ненужни на колбека. В нашия пример за колбека за лампата примерно ми трябва хендъл или име или нещо подобно на лампата и нищо друго (или пък и цвят). [url]Проблемът е, че задължително изисква кърнел, докато решението с калбак работи и с ОС и без ОС.[/url] Е те това е точно така и е огромно предимство на асинхронното - не толкова че може и без ОС. Генералният извод е че е по-независимо от средата. Което включва ОС, HAL, модел на програмиране, архитектура и т.н. Пести всякакъв вид ресурси - на системата де, на фирмата може и да не пести ако програмистите изпитват трудност да го използват). Едит: Не, това е все едно да кажеш че предпочиташ да имаш само един тул - busybox примерно и да викаш него за да ти свърши работата? Реално всяко едно малко тулче което ти описах е еквивален на самостоятелна функция - т.е. алгоритъм. Затова викаш едното, то си свършва работата и точно връща обратно за да ти позволи да повикаш следващото, което повтаря постановката за неговия си алгоритъм. Не излиза "по средата", няма "среда" на работата - това е нещо дето се прави 'run-to-an-end' и е нещо да го кажем атомик. Не можеш да прекъснеш една стъпка от изчислението на PID регулатора, нормалното е да изкараш стъпката до края. Ако някой дефинира по-малки етапи ще направи по-малки инструментчета, това е възможно. Но залитането към правени на по-големи е проблем. В твоята идея те щяха да са навързани предварително в едно голямо exe и щяха да правят цялата последователно (в теорията - процедура, оттам идва процедурно програмиране). Аз покавам че те правя малки, строго дефинирани като алгоритъм стъпки (функции - функционално програмиране), които са толкова изчистени че са преживели 30 години софтуерен развой. Ако имаш за цел да направиш голям и удобен инструмент за по-сложна задача правиш "скрипт" който ползва малките инструментчета. Така не пренаписваш awk а реално си свършил работата бързо и ефективно.
|
| Чет Май 18, 2017 11:51 am |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: RTOSes
gicho, задълбаваш в съвсем друга посока... Пак ти казвам, аз нямам проблем с механизма с калбаци, а липсата на възможност за канселиране в повечето секюрити стекове. При всяка една система за реално време имаш краен срок да се свърши нещо. След като изтече срока, демек след като лопне мандалото гарантирано имаш провал и няма смисъл да продължаваш. То даже и без реал тайм пак си трябва, примерно тръгваш да зареждаш някаква https страничка, обаче не се зарежда и потребителят натиска кръстчето. Нормалното е да канселираш всичко и да се ометеш веднага, а не да остават висящи транзакции, неосвободена памет и т.н.
|
| Чет Май 18, 2017 12:21 pm |
|
 |
|
gicho
Ранг: Форумен бог
Регистриран на: Пон Мар 13, 2006 1:59 pm Мнения: 3867 Местоположение: Габрово
|
 Re: RTOSes
Така де, аз не казвам че таймуатите са излишни или лоши. Ако имаш предвид че подавайки ги през блокиращата функция е по-лесно - да, така е. Но "лесното" е само гледано от специфичната гледна точка на потребителя, даже на някой от потребителите. Няма да задълбавам, идеята е разделение на отговорностите - таймаута се прави някъде си и не е част от драйвера - първо за да не се дублира код (аргумент за таймаут, викане на специфично или абстрактно апи за таймаут). Така се оказва че примерно драйвера ще се окаже в ситуацията да оправя споменатия проблем преди - хем може да му дойде прекъсването за свършена работа, хем може да се обади таймаута. Той с таймаута работа сигурно няма, т.е. не може да определи какво да се прави - просто ще прехвърли този сигнал към "стека".
|
| Чет Май 18, 2017 1:38 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: RTOSes
Така е. Драйверите не се интересуват от таймоути, нито от това дали клиента ще блокира или няма да блокира. Минималната реализация (която и аз съм скрабнал) е от две операции - заявка и IOCTL. При завките няма никаква връзка между клиент и драйвер, освен самата заявка. Клиента си попълва завката (обикновено в хендъла) и я подава на драйверната система. В зависимост от това коя функция вика и как я вика избира дали да блокира или да не блокира. Ако блокира има възможност да укаже таймоут, а ако не блокира може да си избере дали да го сигнализират чрез сигнал или да му викнат калбак. Но драйверът тези неща не ги знае и не го интересуват. Той си получава заявката и когато приключи казва че е приключил и забравя за тая поръчка. Междувременно обаче може да му бъде поискано да прекрати дадена поръчка и ако няма някакви извънредни обстоятелства е редно да я приключи веднага. Няма състезания с прекъсванията, защото тия неща се правят в контекст, който е над всички os-aware ISR-и.
А пък аз тия неща не съм ги измислил, така е долу-горе при всички големи ОС. При мен поради разбираеми причини съм опростил някои неща. Други съм усложнил, примерно при блокиращо/таймоут викане се налага да се проверява резултата както казваш. Причината е, че не поддържам ексепшъни както е при големите батковци. Ако ги поддържах, то можеше да симулирам едно throw, а клиентът да си го прифаща както и където иска. Но пък тая глезотия си има други недостатъци, тъй че няма пълно щастие!
|
| Чет Май 18, 2017 2:46 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: RTOSes
SLIBIO/SLib - интересна библиотечка, с доста неща на тема обработка данни, рендване, криптиране, комуникация. Правена е като за мултиплатформена и кодът е доста чист, така че би могъл да се ползва и в малки емебдед системки.
|
| Пет Май 19, 2017 12:02 pm |
|
 |
|
miro_atc
Ранг: Форумен бог
Регистриран на: Нед Фев 26, 2006 6:52 pm Мнения: 11266 Местоположение: Добрич
|
 Re: RTOSes
|
| Пет Май 26, 2017 12:03 pm |
|
 |
|
palavrov
Ранг: Форумен бог
Регистриран на: Вто Окт 11, 2011 11:53 pm Мнения: 4582 Местоположение: Brussels / Пловдив
|
 Re: RTOSes
Нещо не им върви с овцете последно време ...
_________________ Мразя да мразя ...
|
| Пет Май 26, 2017 1:33 pm |
|
|
Кой е на линия |
Потребители разглеждащи този форум: 0 регистрирани и 10 госта |
|
Вие не можете да пускате нови теми Вие не можете да отговаряте на теми Вие не можете да променяте собственото си мнение Вие не можете да изтривате собствените си мнения Вие не можете да прикачвате файл
|
|