| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967 |
- <?xml version="1.0" encoding="UTF-8"?>
- <model version="5.2.5" links="1">
- <documentation>QP/C Real-Time Embedded Framework (RTEF)
- The model is used to generate the whole QP/C source code.
- Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
- SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
- This software is dual-licensed under the terms of the open source GNU
- General Public License version 3 (or any later version), or alternatively,
- under the terms of one of the closed source Quantum Leaps commercial
- licenses.
- The terms of the open source GNU General Public License version 3
- can be found at: <www.gnu.org/licenses/gpl-3.0>
- The terms of the closed source Quantum Leaps commercial licenses
- can be found at: <www.state-machine.com/licensing>
- Redistributions in source code must retain this copyright notice.
- Plagiarizing this software to sidestep the license obligations is illegal.
- Contact information:
- <www.state-machine.com/licensing>
- <info@state-machine.com></documentation>
- <!--${qpc}-->
- <framework name="qpc" license="LICENSES/LicenseRef-QL-dual.qlc"/>
- <!--${DbC}-->
- <package name="DbC" stereotype="0x05">
- <!--${DbC::active}-->
- <package name="active" stereotype="0x05">
- <!--${DbC::active::Q_DEFINE_THIS_MODULE}-->
- <operation name="Q_DEFINE_THIS_MODULE" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Define the user-specified module name for assertions in this file.
- *
- * @details
- * Macro to be placed at the top of each C/C++ module to define the
- * single instance of the module name string to be used in reporting
- * assertions in this module. This macro takes the user-supplied parameter
- * `name_` instead of `__FILE__` to precisely control the name of the
- * module.
- *
- * @param[in] name_ string constant representing the module name
- *
- * @note
- * This macro should **not** be terminated by a semicolon.
- */</documentation>
- <!--${DbC::active::Q_DEFINE_THIS_MO~::name_}-->
- <parameter name="name_" type="char const *"/>
- <code>\
- static char const Q_this_module_[] = name_;</code>
- </operation>
- <!--${DbC::active::Q_ASSERT_ID}-->
- <operation name="Q_ASSERT_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! General-purpose assertion with user-specified ID number.
- *
- * @details
- * Evaluates the Boolean expression `expr_` and does nothing else when
- * it evaluates to 'true'. However, when `expr_` evaluates to 'false',
- * the Q_ASSERT_ID() macro calls the no-return function Q_onAssert().
- *
- * @param[in] id_ ID number (unique within the module) of the assertion
- * @param[in] expr_ Boolean expression to check
- *
- * @attention
- * When assertions are disabled (by defining the ::Q_NASSERT macro), the
- * Q_ASSERT_ID() macro expands to nothing, and consequently the Boolean
- * expression `expr_` is **not** evaluated and the callback function
- * Q_onAssert() is **not** called.
- */</documentation>
- <!--${DbC::active::Q_ASSERT_ID::id_}-->
- <parameter name="id_" type="int"/>
- <!--${DbC::active::Q_ASSERT_ID::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>((expr_) \
- ? ((void)0) : Q_onAssert(&Q_this_module_[0], (id_)))</code>
- </operation>
- <!--${DbC::active::Q_ERROR_ID}-->
- <operation name="Q_ERROR_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Assertion with user-specified ID for a wrong path through the code
- *
- * @details
- * Calls the Q_onAssert() callback if ever executed. This assertion
- * takes the user-supplied parameter `id_` to identify the location of
- * this assertion within the file. This avoids the volatility of using
- * line numbers, which change whenever a line of code is added or removed
- * upstream from the assertion.
- *
- * @param[in] id_ ID number (unique within the module) of the assertion
- *
- * @note
- * Does noting if assertions are disabled with the ::Q_NASSERT switch.
- */</documentation>
- <!--${DbC::active::Q_ERROR_ID::id_}-->
- <parameter name="id_" type="int"/>
- <code>Q_onAssert(&Q_this_module_[0], (id_))</code>
- </operation>
- <!--${DbC::active::Q_ALLEGE_ID}-->
- <operation name="Q_ALLEGE_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! General purpose assertion with user-specified ID number that
- * **always** evaluates the `expr_` expression.
- *
- * @details
- * Like the Q_ASSERT_ID() macro, except it **always** evaluates the
- * `expr_` expression even when assertions are disabled with the
- * ::Q_NASSERT macro. However, when the ::Q_NASSERT macro is defined, the
- * Q_onAssert() callback is **not** called, even if `expr_` evaluates
- * to FALSE.
- *
- * @param[in] id_ ID number (unique within the module) of the assertion
- * @param[in] expr_ Boolean expression to check
- */</documentation>
- <!--${DbC::active::Q_ALLEGE_ID::id_}-->
- <parameter name="id_" type="int"/>
- <!--${DbC::active::Q_ALLEGE_ID::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>Q_ASSERT_ID((id_), (expr_))</code>
- </operation>
- </package>
- <!--${DbC::inactive}-->
- <package name="inactive" stereotype="0x05">
- <!--${DbC::inactive::Q_DEFINE_THIS_MODULE}-->
- <operation name="Q_DEFINE_THIS_MODULE" type="" visibility="0x03" properties="0x00">
- <documentation>/*! inactive version of Q_DEFINE_THIS_MODULE() */</documentation>
- <!--${DbC::inactive::Q_DEFINE_THIS_MO~::name_}-->
- <parameter name="name_" type="char const *"/>
- </operation>
- <!--${DbC::inactive::Q_ASSERT_ID}-->
- <operation name="Q_ASSERT_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! inactive version of Q_ASSERT_ID() */</documentation>
- <!--${DbC::inactive::Q_ASSERT_ID::id_}-->
- <parameter name="id_" type="int"/>
- <!--${DbC::inactive::Q_ASSERT_ID::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>((void)0)</code>
- </operation>
- <!--${DbC::inactive::Q_ERROR_ID}-->
- <operation name="Q_ERROR_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! inactive version of Q_ERROR_ID() */</documentation>
- <!--${DbC::inactive::Q_ERROR_ID::id_}-->
- <parameter name="id_" type="int"/>
- <code>((void)0)</code>
- </operation>
- <!--${DbC::inactive::Q_ALLEGE_ID}-->
- <operation name="Q_ALLEGE_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! inactive version of Q_ALLEGE_ID()
- *
- * @attention
- * The expression `expr_` **is** evaluated, even though assertion
- * callback Q_onAssert() is NOT called when `expr_` evaluates to
- * false.
- */</documentation>
- <!--${DbC::inactive::Q_ALLEGE_ID::id_}-->
- <parameter name="id_" type="int"/>
- <!--${DbC::inactive::Q_ALLEGE_ID::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>((void)(expr_))</code>
- </operation>
- </package>
- <!--${DbC::Q_DEFINE_THIS_FILE}-->
- <attribute name="Q_DEFINE_THIS_FILE" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Define the file name (with `__FILE__`) for assertions in this file
- *
- * @details
- * Macro to be placed at the top of each C/C++ module to define the
- * single instance of the file name string to be used in reporting
- * assertions in this module.
- *
- * @note
- * The file name string literal is defined by means of the standard
- * preprocessor macro `__FILE__`. However, please note that, depending
- * on the compiler, the `__FILE__` macro might contain the whole path name
- * to the file, which might be inconvenient to log assertions.
- *
- * @attention
- * This macro should **not** be terminated by a semicolon.
- *
- * @sa Q_DEFINE_THIS_MODULE()
- */</documentation>
- <code>Q_DEFINE_THIS_MODULE(__FILE__)</code>
- </attribute>
- <!--${DbC::Q_ASSERT}-->
- <operation name="Q_ASSERT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! General-purpose assertion (with __LINE__ used as location in the file)
- *
- * @details
- * Equivalent to Q_ASSERT_ID(), except it uses __LINE__ to identify the
- * assertion within a file.
- *
- * @param[in] expr_ Boolean expression to check
- *
- * @sa Q_ASSERT_ID()
- */</documentation>
- <!--${DbC::Q_ASSERT::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>Q_ASSERT_ID(__LINE__, (expr_))</code>
- </operation>
- <!--${DbC::Q_ERROR}-->
- <operation name="Q_ERROR" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Assertion for a wrong path through the code
- *
- * @details
- * Calls the Q_onAssert() callback if ever executed.
- *
- * @note
- * This macro identifies the problem location with the line number,
- * which might change as the code is modified.
- *
- * @sa Q_ERROR_ID()
- */</documentation>
- <code>Q_ERROR_ID(__LINE__)</code>
- </operation>
- <!--${DbC::Q_REQUIRE_ID}-->
- <operation name="Q_REQUIRE_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Assertion for checking **preconditions**.
- *
- * @details
- * Equivalent to Q_ASSERT_ID(), except the name provides a better
- * documentation of the intention of this assertion.
- *
- * @param[in] id_ ID number (unique within the module) of the assertion
- * @param[in] expr_ Boolean expression
- */</documentation>
- <!--${DbC::Q_REQUIRE_ID::id_}-->
- <parameter name="id_" type="int"/>
- <!--${DbC::Q_REQUIRE_ID::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>Q_ASSERT_ID((id_), (expr_))</code>
- </operation>
- <!--${DbC::Q_REQUIRE}-->
- <operation name="Q_REQUIRE" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Assertion for checking preconditions (based on __LINE__).
- *
- * @details
- * Equivalent to Q_ASSERT(), except the name provides a better documentation
- * of the intention of this assertion.
- *
- * @param[in] expr_ Boolean expression
- */</documentation>
- <!--${DbC::Q_REQUIRE::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>Q_ASSERT(expr_)</code>
- </operation>
- <!--${DbC::Q_ENSURE_ID}-->
- <operation name="Q_ENSURE_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Assertion for checking postconditions.
- *
- * @details
- * Equivalent to Q_ASSERT_ID(), except the name provides a better documentation
- * of the intention of this assertion.
- *
- * @param[in] id_ ID number (unique within the module) of the assertion
- * @param[in] expr_ Boolean expression
- */</documentation>
- <!--${DbC::Q_ENSURE_ID::id_}-->
- <parameter name="id_" type="int"/>
- <!--${DbC::Q_ENSURE_ID::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>Q_ASSERT_ID((id_), (expr_))</code>
- </operation>
- <!--${DbC::Q_ENSURE}-->
- <operation name="Q_ENSURE" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Assertion for checking postconditions.
- *
- * @details
- * Equivalent to Q_ASSERT(), except the name provides a better documentation
- * of the intention of this assertion.
- *
- * @param[in] expr_ Boolean expression
- */</documentation>
- <!--${DbC::Q_ENSURE::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>Q_ASSERT(expr_)</code>
- </operation>
- <!--${DbC::Q_INVARIANT_ID}-->
- <operation name="Q_INVARIANT_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Assertion for checking invariants.
- *
- * @details
- * Equivalent to Q_ASSERT_ID(), except the name provides a better
- * documentation of the intention of this assertion.
- *
- * @param[in] id_ ID number (unique within the module) of the assertion
- * @param[in] expr_ Boolean expression
- */</documentation>
- <!--${DbC::Q_INVARIANT_ID::id_}-->
- <parameter name="id_" type="int"/>
- <!--${DbC::Q_INVARIANT_ID::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>Q_ASSERT_ID((id_), (expr_))</code>
- </operation>
- <!--${DbC::Q_INVARIANT}-->
- <operation name="Q_INVARIANT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Assertion for checking invariants.
- *
- * @details
- * Equivalent to Q_ASSERT(), except the name provides a better documentation
- * of the intention of this assertion.
- *
- * @param[in] expr_ Boolean expression
- */</documentation>
- <!--${DbC::Q_INVARIANT::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>Q_ASSERT(expr_)</code>
- </operation>
- <!--${DbC::Q_ALLEGE}-->
- <operation name="Q_ALLEGE" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! General purpose assertion with user-specified ID number that
- * **always** evaluates the `expr_` expression.
- *
- * @details
- * Equivalent to Q_ALLEGE_ID(), except it identifies the problem location
- * with the line number `__LINE__`, which might change as the code is modified.
- *
- * @param[in] expr_ Boolean expression to check
- *
- * @sa Q_ALLEGE_ID()
- */</documentation>
- <!--${DbC::Q_ALLEGE::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>Q_ALLEGE_ID(__LINE__, (expr_))</code>
- </operation>
- <!--${DbC::Q_ASSERT_STATIC}-->
- <operation name="Q_ASSERT_STATIC" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Static (compile-time) assertion.
- *
- * @details
- * This type of assertion deliberately causes a compile-time error when
- * the `expr_` Boolean expression evaluates to FALSE. The macro exploits
- * the fact that in C/C++ a dimension of an array cannot be negative.
- * The compile-time assertion has no runtime side effects.
- *
- * @param[in] expr_ Compile-time Boolean expression
- *
- * @note
- * The static assertion macro is provided for backwards compatibility with
- * older C standards. Newer C11 supports `_Static_assert()`, which should
- * be used instead of Q_ASSERT_STATIC().
- */</documentation>
- <!--${DbC::Q_ASSERT_STATIC::expr_}-->
- <parameter name="expr_" type="bool"/>
- <code>extern char Q_static_assert_[(expr_) ? 1 : -1]</code>
- </operation>
- <!--${DbC::Q_NORETURN}-->
- <attribute name="Q_NORETURN?ndef Q_NORETURN" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! No-return function specifier for the Q_onAssert() callback function.
- *
- * @details
- * If the `Q_NORETURN` macro is undefined, the default definition uses
- * the C99 specifier `_Noreturn`.
- *
- * @note
- * The `Q_NORETURN` macro can be defined in the QP port (typically in
- * `qep_port.h` or `qep_port.hpp`). If such definition is porvided
- * the default won't be used.
- *
- * @trace
- * @tr{PQA01_4}
- */</documentation>
- <code>_Noreturn void</code>
- </attribute>
- <!--${DbC::int_t}-->
- <attribute name="int_t?ndef QP_VERSION" type="typedef int" visibility="0x04" properties="0x00">
- <documentation>/*! typedef for assertions-ids and line numbers in assertions.
- *
- * @details
- * This typedef specifies integer type for exclusive use in assertions.
- * Use of this type, rather than plain 'int', is in compliance
- * with the MISRA-C 2012 Dir 4.6 (adv).
- */</documentation>
- </attribute>
- <!--${DbC::Q_onAssert}-->
- <operation name="Q_onAssert" type="Q_NORETURN" visibility="0x00" properties="0x00">
- <documentation>/*! Callback function invoked in case of an assertion failure.
- *
- * @details
- * This callback function needs to be defined in the application to perform
- * any corrective action after a non-recoverable error has been detected.
- * The Q_onAssert() function is the last line of defense after the
- * system failure and its implementation shouild be very **carefully**
- * designed and **tested** under various fault conditions, including but
- * not limited to: stack overflow, stack corruption, or calling Q_onAssert()
- * from an interrupt.
- *
- * @param[in] module name of the file/module in which the assertion failed
- * (constant, zero-terminated C string)
- * @param[in] location location of the assertion within the module. This could
- * be a line number or a user-specified ID-number.
- *
- * @returns
- * This callback function should **not return** (see ::Q_NORETURN),
- * as continuation after an assertion failure does not make sense.
- *
- * @note
- * During debugging, Q_onAssert() is an ideal place to put a breakpoint.
- * For deployment, tt is typically a **bad idea** to implement Q_onAssert()
- * as an endless loop that ties up the CPU (denial of service).
- *
- * Called by the following: Q_ASSERT_ID(), Q_ERROR_ID(), Q_REQUIRE_ID(),
- * Q_ENSURE_ID(), Q_INVARIANT_ID() and Q_ALLEGE_ID() as well as:
- * Q_ASSERT(), Q_ERROR(), Q_REQUIRE(), Q_ENSURE(), Q_INVARIANT(),
- * and Q_ALLEGE().
- *
- * @trace
- * @tr{PQA01_4}
- */</documentation>
- <!--${DbC::Q_onAssert::module}-->
- <parameter name="module" type="char const *"/>
- <!--${DbC::Q_onAssert::location}-->
- <parameter name="location" type="int_t"/>
- </operation>
- <!--${DbC::Q_DIM}-->
- <operation name="Q_DIM?ndef QP_VERSION" type="unsigned" visibility="0x03" properties="0x00">
- <documentation>/*! Helper macro to calculate static dimension of a 1-dim `array_`
- *
- * @param array_ 1-dimensional array
- * @returns the length of the array (number of elements it can hold)
- */</documentation>
- <!--${DbC::Q_DIM::array_}-->
- <parameter name="array_" type="1-dimensional array"/>
- <code>(sizeof(array_) / sizeof((array_)[0U]))</code>
- </operation>
- </package>
- <!--${glob-types}-->
- <package name="glob-types" stereotype="0x00">
- <!--${glob-types::int_t}-->
- <attribute name="int_t" type="typedef int" visibility="0x04" properties="0x00">
- <documentation>/*! alias for line numbers in assertions and return from QF_run() */</documentation>
- </attribute>
- <!--${glob-types::enum_t}-->
- <attribute name="enum_t" type="typedef int" visibility="0x04" properties="0x00">
- <documentation>/*! alias for enumerations used for event signals */</documentation>
- </attribute>
- <!--${glob-types::float32_t}-->
- <attribute name="float32_t" type="typedef float" visibility="0x04" properties="0x00">
- <documentation>/*! alias for IEEE 754 32-bit floating point number,
- * MISRA-C 2012 Dir 4.6(A)
- *
- * @note
- * QP does not use floating-point types anywhere in the internal
- * implementation, except in QS software tracing, where utilities for
- * output of floating-point numbers are provided for application-specific
- * trace records.
- */</documentation>
- </attribute>
- <!--${glob-types::float64_t}-->
- <attribute name="float64_t" type="typedef double" visibility="0x04" properties="0x00">
- <documentation>/*! alias for IEEE 754 64-bit floating point number,
- * MISRA-C 2012 Dir 4.6(A)
- *
- * @note
- * QP does not use floating-point types anywhere in the internal
- * implementation, except in QS software tracing, where utilities for
- * output of floating-point numbers are provided for application-specific
- * trace records.
- */</documentation>
- </attribute>
- </package>
- <!--${QEP-config}-->
- <package name="QEP-config" stereotype="0x02">
- <!--${QEP-config::Q_SIGNAL_SIZE}-->
- <attribute name="Q_SIGNAL_SIZE?ndef Q_SIGNAL_SIZE" type="" visibility="0x03" properties="0x00">
- <documentation>/*! The size (in bytes) of the signal of an event. Valid values:
- * 1U, 2U, or 4U; default 2U
- *
- * @details
- * This macro can be defined in the QEP port file (qep_port.h) to
- * configure the ::QSignal type. When the macro is not defined, the
- * default of 2 bytes is applied.
- */</documentation>
- <code>2U</code>
- </attribute>
- </package>
- <!--${QEP-macros}-->
- <package name="QEP-macros" stereotype="0x02">
- <!--${QEP-macros::QHSM_INIT}-->
- <operation name="QHSM_INIT?def Q_SPY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Virtual call to the top-most initial transition in a HSM.
- *
- * @param[in,out] me_ current instance pointer (see @ref oop)
- * @param[in] par_ pointer the optional initialization parameter
- * @param[in] qs_id_ QS local filter ID (used only when Q_SPY is defined)
- *
- * @note Must be called only ONCE after the SM "constructor".
- *
- * @trace
- * @tr{RQP102}
- *
- * @usage
- * The following example illustrates how to initialize a SM, and dispatch
- * events to it:
- * @include qep_qhsm_use.c
- */</documentation>
- <!--${QEP-macros::QHSM_INIT::me_}-->
- <parameter name="me_" type="<QHsm subclass*>"/>
- <!--${QEP-macros::QHSM_INIT::par_}-->
- <parameter name="par_" type="void *"/>
- <!--${QEP-macros::QHSM_INIT::qs_id_}-->
- <parameter name="qs_id_" type="uint8_t"/>
- <code>do { \
- Q_ASSERT((me_)->vptr); \
- (*(me_)->vptr->init)((me_), (par_), (qs_id_)); \
- } while (false)</code>
- </operation>
- <!--${QEP-macros::QHSM_INIT}-->
- <operation name="QHSM_INIT?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
- <!--${QEP-macros::QHSM_INIT::me_}-->
- <parameter name="me_" type="<QHsm subclass*>"/>
- <!--${QEP-macros::QHSM_INIT::par_}-->
- <parameter name="par_" type="void *"/>
- <!--${QEP-macros::QHSM_INIT::dummy}-->
- <parameter name="dummy" type=""/>
- <code>do { \
- Q_ASSERT((me_)->vptr); \
- (*(me_)->vptr->init)((me_), (par_), 0U); \
- } while (false)</code>
- </operation>
- <!--${QEP-macros::QHSM_DISPATCH}-->
- <operation name="QHSM_DISPATCH?def Q_SPY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Virtual call to dispatch an event to a HSM
- *
- * @details
- * Processes one event at a time in Run-to-Completion fashion.
- *
- * @param[in,out] me_ current instance pointer (see @ref oop)
- * @param[in] e_ constant pointer the ::QEvt or a class
- * derived from ::QEvt (see @ref oop)
- * @param[in] qs_id_ QS local filter ID (used only when Q_SPY is defined)
- *
- * @note Must be called after the "constructor" and after QHSM_INIT().
- *
- * @trace
- * @tr{RQP102}
- */</documentation>
- <!--${QEP-macros::QHSM_DISPATCH::me_}-->
- <parameter name="me_" type="<QHsm subclass*>"/>
- <!--${QEP-macros::QHSM_DISPATCH::e_}-->
- <parameter name="e_" type="QEvt *"/>
- <!--${QEP-macros::QHSM_DISPATCH::qs_id_}-->
- <parameter name="qs_id_" type="uint8_t"/>
- <code>\
- ((*(me_)->vptr->dispatch)((me_), (e_), (qs_id_)))</code>
- </operation>
- <!--${QEP-macros::QHSM_DISPATCH}-->
- <operation name="QHSM_DISPATCH?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
- <!--${QEP-macros::QHSM_DISPATCH::me_}-->
- <parameter name="me_" type="<QHsm subclass*>"/>
- <!--${QEP-macros::QHSM_DISPATCH::e_}-->
- <parameter name="e_" type="QEvt *"/>
- <!--${QEP-macros::QHSM_DISPATCH::dummy}-->
- <parameter name="dummy" type=""/>
- <code>\
- ((*(me_)->vptr->dispatch)((me_), (e_), 0U))</code>
- </operation>
- <!--${QEP-macros::Q_HSM_UPCAST}-->
- <operation name="Q_HSM_UPCAST" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Perform upcast from a subclass of ::QHsm to the base class ::QHsm
- *
- * @details
- * Upcasting from a subclass to superclass is a very frequent and **safe**
- * operation in object-oriented programming and object-oriented languages
- * (such as C++) perform such upcasting automatically. However, OOP is
- * implemented in C just as a set of coding conventions (see @ref oop),
- * and the C compiler does not "know" that certain types are related by
- * inheritance. Therefore for C, the upcast must be performed explicitly.
- * Unfortunately, pointer casting violates the advisory MISRA-C 2012
- * Rule 11.3(req) "A cast shall not be performed between a pointer to object
- * type and a pointer to a different object type". This macro encapsulates
- * this deviation and provides a descriptive name for the reason of this cast.
- */</documentation>
- <!--${QEP-macros::Q_HSM_UPCAST::ptr_}-->
- <parameter name="ptr_" type="<QHsm subclass*>"/>
- <code>((QHsm *)(ptr_))</code>
- </operation>
- <!--${QEP-macros::Q_TRAN}-->
- <operation name="Q_TRAN" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Perform upcast from a subclass of ::QHsm to the base class ::QHsm
- *
- * @details
- * Upcasting from a subclass to superclass is a very frequent and **safe**
- * operation in object-oriented programming and object-oriented languages
- * (such as C++) perform such upcasting automatically. However, OOP is
- * implemented in C just as a set of coding conventions (see @ref oop),
- * and the C compiler does not "know" that certain types are related by
- * inheritance. Therefore for C, the upcast must be performed explicitly.
- * Unfortunately, pointer casting violates the advisory MISRA-C 2012
- * Rule 11.3(req) "A cast shall not be performed between a pointer to object
- * type and a pointer to a different object type". This macro encapsulates
- * this deviation and provides a descriptive name for the reason of this cast.
- */</documentation>
- <!--${QEP-macros::Q_TRAN::target_}-->
- <parameter name="target_" type="QStateHandler"/>
- <code>\
- ((Q_HSM_UPCAST(me))->temp.fun = Q_STATE_CAST(target_), Q_RET_TRAN)</code>
- </operation>
- <!--${QEP-macros::Q_TRAN_HIST}-->
- <operation name="Q_TRAN_HIST" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a state-handler when it executes a transition
- * to history. Applicable only to HSMs.
- *
- * @trace
- * @tr{RQP103}, @tr{RQP120H}
- *
- * @usage
- * @include qep_qhist.c
- */</documentation>
- <!--${QEP-macros::Q_TRAN_HIST::hist_}-->
- <parameter name="hist_" type="QStateHandler"/>
- <code>\
- ((Q_HSM_UPCAST(me))->temp.fun = (hist_), Q_RET_TRAN_HIST)</code>
- </operation>
- <!--${QEP-macros::Q_SUPER}-->
- <operation name="Q_SUPER" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a state-handler when it designates the superstate
- * of a given state. Applicable only to ::QHsm subclasses.
- *
- * @trace
- * @tr{RQP103}
- *
- * @usage
- * @include qep_qsuper.c
- */</documentation>
- <!--${QEP-macros::Q_SUPER::super_}-->
- <parameter name="super_" type="QStateHandler"/>
- <code>\
- ((Q_HSM_UPCAST(me))->temp.fun = Q_STATE_CAST(super_), Q_RET_SUPER)</code>
- </operation>
- <!--${QEP-macros::Q_HANDLED}-->
- <operation name="Q_HANDLED" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a state-handler when it handles an event.
- *
- * @trace
- * @tr{RQP103}, @tr{RQP120B}, @tr{RQP120C}
- */</documentation>
- <code>(Q_RET_HANDLED)</code>
- </operation>
- <!--${QEP-macros::Q_UNHANDLED}-->
- <operation name="Q_UNHANDLED" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a state-handler when it attempts to handle
- * an event but a guard condition evaluates to 'false' and there is no other
- * explicit way of handling the event. Applicable only to ::QHsm subclasses.
- */</documentation>
- <code>(Q_RET_UNHANDLED)</code>
- </operation>
- <!--${QEP-macros::Q_ACTION_NULL}-->
- <attribute name="Q_ACTION_NULL" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to provide strictly-typed zero-action to terminate action lists
- *! in the transition-action-tables
- */</documentation>
- <code>((QActionHandler)0)</code>
- </attribute>
- <!--${QEP-macros::Q_EVT_CAST}-->
- <operation name="Q_EVT_CAST" type="<QEvt subclass>*" visibility="0x03" properties="0x00">
- <documentation>/*! Perform downcast of an event onto a subclass of ::QEvt `class_`
- *
- * @details
- * This macro encapsulates the downcast of ::QEvt pointers, which violates
- * MISRA-C 2012 Rule 11.3(R) "A cast shall not be performed between a
- * pointer to object type and a pointer to a different object type". This
- * macro helps to localize this deviation.
- *
- * @param class_ a subclass of ::QEvt
- *
- * @trace
- * @tr{RQP003}, @tr{PQA11_3}
- */</documentation>
- <!--${QEP-macros::Q_EVT_CAST::class_}-->
- <parameter name="class_" type="<QEvt subclass>"/>
- <code>((class_ const *)(e))</code>
- </operation>
- <!--${QEP-macros::Q_STATE_CAST}-->
- <operation name="Q_STATE_CAST" type="QStateHandler" visibility="0x03" properties="0x00">
- <documentation>/*! Perform cast to ::QStateHandler.
- * @details
- * This macro encapsulates the cast of a specific state handler function
- * pointer to ::QStateHandler, which violates MISRA:C-2012 Rule 11.1(req)
- * "Conversions shall not be performed between a pointer to function and
- * any other type". This macro helps to localize this deviation.
- *
- * @trace
- * @tr{PQP11_1}, @tr{PQA11_1}
- *
- * @usage
- * @include qep_qhsm_ctor.c
- */</documentation>
- <!--${QEP-macros::Q_STATE_CAST::handler_}-->
- <parameter name="handler_" type="<state handler>"/>
- <code>((QStateHandler)(handler_))</code>
- </operation>
- <!--${QEP-macros::Q_ACTION_CAST}-->
- <operation name="Q_ACTION_CAST" type="QActionHandler" visibility="0x03" properties="0x00">
- <documentation>/*! Perform cast to ::QActionHandler.
- * @details
- * This macro encapsulates the cast of a specific action handler function
- * pointer to ::QActionHandler, which violates MISRA:C-2012 Rule 11.1(R)
- * "Conversions shall not be performed between a pointer to function and
- * any other type". This macro helps to localize this deviation.
- *
- * @trace
- * @tr{PQP11_1}, @tr{PQA11_1}
- */</documentation>
- <!--${QEP-macros::Q_ACTION_CAST::action_}-->
- <parameter name="action_" type="<action handler>"/>
- <code>((QActionHandler)(action_))</code>
- </operation>
- <!--${QEP-macros::Q_UNUSED_PAR}-->
- <operation name="Q_UNUSED_PAR" type="<param type>" visibility="0x03" properties="0x00">
- <documentation>/*! Helper macro to clearly mark unused parameters of functions. */</documentation>
- <!--${QEP-macros::Q_UNUSED_PAR::par_}-->
- <parameter name="par_" type="<param type>"/>
- <code>((void)(par_))</code>
- </operation>
- <!--${QEP-macros::Q_DIM}-->
- <operation name="Q_DIM" type="unsigned" visibility="0x03" properties="0x00">
- <documentation>/*! Helper macro to calculate static dimension of a 1-dim `array_`
- *
- * @param array_ 1-dimensional array
- * @returns the length of the array (number of elements it can hold)
- */</documentation>
- <!--${QEP-macros::Q_DIM::array_}-->
- <parameter name="array_" type="1-dimensional array"/>
- <code>(sizeof(array_) / sizeof((array_)[0U]))</code>
- </operation>
- <!--${QEP-macros::Q_UINT2PTR_CAST}-->
- <operation name="Q_UINT2PTR_CAST" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Perform cast from unsigned integer `uint_` to pointer of type `type_`
- *
- * @details
- * This macro encapsulates the cast to (type_ *), which QP ports or
- * application might use to access embedded hardware registers.
- * Such uses can trigger PC-Lint "Note 923: cast from int to pointer"
- * and this macro helps to encapsulate this deviation.
- */</documentation>
- <!--${QEP-macros::Q_UINT2PTR_CAST::type_}-->
- <parameter name="type_" type=""/>
- <!--${QEP-macros::Q_UINT2PTR_CAST::uint_}-->
- <parameter name="uint_" type=""/>
- <code>((type_ *)(uint_))</code>
- </operation>
- <!--${QEP-macros::QEVT_INITIALIZER}-->
- <operation name="QEVT_INITIALIZER" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Initializer of static constant QEvt instances
- *
- * @details
- * This macro encapsulates the ugly casting of enumerated signals
- * to QSignal and constants for QEvt.poolID and QEvt.refCtr_.
- */</documentation>
- <!--${QEP-macros::QEVT_INITIALIZER::sig_}-->
- <parameter name="sig_" type="QSignal"/>
- <code>{ (QSignal)(sig_), 0U, 0U }</code>
- </operation>
- <!--${QEP-macros::QM_ENTRY}-->
- <operation name="QM_ENTRY?def Q_SPY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM action-handler when it executes
- * an entry action. Applicable only to ::QMsm subclasses.
- */</documentation>
- <!--${QEP-macros::QM_ENTRY::state_}-->
- <parameter name="state_" type="QStateHandler"/>
- <code>\
- ((Q_HSM_UPCAST(me))->temp.obj = (state_), Q_RET_ENTRY)</code>
- </operation>
- <!--${QEP-macros::QM_ENTRY}-->
- <operation name="QM_ENTRY?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
- <!--${QEP-macros::QM_ENTRY::dummy}-->
- <parameter name="dummy" type=""/>
- <code>(Q_RET_ENTRY)</code>
- </operation>
- <!--${QEP-macros::QM_EXIT}-->
- <operation name="QM_EXIT?def Q_SPY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM action-handler when it executes
- * an exit action. Applicable only to ::QMsm subclasses.
- */</documentation>
- <!--${QEP-macros::QM_EXIT::state_}-->
- <parameter name="state_" type="QStateHandler"/>
- <code>\
- ((Q_HSM_UPCAST(me))->temp.obj = (state_), Q_RET_EXIT)</code>
- </operation>
- <!--${QEP-macros::QM_EXIT}-->
- <operation name="QM_EXIT?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
- <!--${QEP-macros::QM_EXIT::dummy}-->
- <parameter name="dummy" type=""/>
- <code>(Q_RET_EXIT)</code>
- </operation>
- <!--${QEP-macros::QM_SM_EXIT}-->
- <operation name="QM_SM_EXIT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM submachine exit-handler.
- * Applicable only to subclasses of ::QMsm.
- */</documentation>
- <!--${QEP-macros::QM_SM_EXIT::state_}-->
- <parameter name="state_" type="QStateHandler"/>
- <code>\
- ((Q_HSM_UPCAST(me))->temp.obj = (state_), Q_RET_EXIT)</code>
- </operation>
- <!--${QEP-macros::QM_TRAN}-->
- <operation name="QM_TRAN" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM state-handler when it executes a regular
- * transition. Applicable only to ::QMsm subclasses.
- */</documentation>
- <!--${QEP-macros::QM_TRAN::tatbl_}-->
- <parameter name="tatbl_" type="QMTranActionTable const *"/>
- <code>((Q_HSM_UPCAST(me))->temp.tatbl \
- = (struct QMTranActTable const *)(tatbl_), Q_RET_TRAN)</code>
- </operation>
- <!--${QEP-macros::QM_TRAN_INIT}-->
- <operation name="QM_TRAN_INIT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM state-handler when it executes an initial
- * transition. Applicable only to ::QMsm subclasses.
- */</documentation>
- <!--${QEP-macros::QM_TRAN_INIT::tatbl_}-->
- <parameter name="tatbl_" type="QMTranActionTable const *"/>
- <code>((Q_HSM_UPCAST(me))->temp.tatbl \
- = (struct QMTranActTable const *)(tatbl_), Q_RET_TRAN_INIT)</code>
- </operation>
- <!--${QEP-macros::QM_TRAN_HIST}-->
- <operation name="QM_TRAN_HIST" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM state-handler when it executes a transition
- * to history. Applicable only to ::QMsm subclasses.
- */</documentation>
- <!--${QEP-macros::QM_TRAN_HIST::history_}-->
- <parameter name="history_" type="QStateHandler"/>
- <!--${QEP-macros::QM_TRAN_HIST::tatbl_}-->
- <parameter name="tatbl_" type="QMTranActionTable const *"/>
- <code>\
- ((((Q_HSM_UPCAST(me))->state.obj = (history_)), \
- ((Q_HSM_UPCAST(me))->temp.tatbl = \
- (struct QMTranActTable const *)(tatbl_))), \
- Q_RET_TRAN_HIST)</code>
- </operation>
- <!--${QEP-macros::QM_TRAN_EP}-->
- <operation name="QM_TRAN_EP" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM state-handler when it executes a transition
- * to the submachine via an entry point.
- */</documentation>
- <!--${QEP-macros::QM_TRAN_EP::tatbl_}-->
- <parameter name="tatbl_" type="QMTranActionTable const *"/>
- <code>((Q_HSM_UPCAST(me))->temp.tatbl \
- = (struct QMTranActTable const *)(tatbl_), Q_RET_TRAN_EP)</code>
- </operation>
- <!--${QEP-macros::QM_TRAN_XP}-->
- <operation name="QM_TRAN_XP" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM state-handler when it executes a transition
- * to exit point. Applicable only to ::QMsm subclasses.
- */</documentation>
- <!--${QEP-macros::QM_TRAN_XP::xp_}-->
- <parameter name="xp_" type="QStateHandler"/>
- <!--${QEP-macros::QM_TRAN_XP::tatbl_}-->
- <parameter name="tatbl_" type="QMTranActionTable const *"/>
- <code>\
- ((((Q_HSM_UPCAST(me))->state.act = (xp_)), \
- ((Q_HSM_UPCAST(me))->temp.tatbl = \
- (struct QMTranActTable const *)(tatbl_))), \
- Q_RET_TRAN_XP)</code>
- </operation>
- <!--${QEP-macros::QM_HANDLED}-->
- <operation name="QM_HANDLED" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM state-handler when it handled an event.
- * Applicable only to ::QMsm subclasses.
- */</documentation>
- <code>(Q_RET_HANDLED)</code>
- </operation>
- <!--${QEP-macros::QM_UNHANDLED}-->
- <operation name="QM_UNHANDLED" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM state-handler when when it attempts to
- * handle an event but a guard condition evaluates to 'false' and there is
- * no other explicit way of handling the event. Applicable only to
- * ::QMsm subclasses.
- */</documentation>
- <code>(Q_RET_UNHANDLED)</code>
- </operation>
- <!--${QEP-macros::QM_SUPER}-->
- <operation name="QM_SUPER" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM state-handler when it designates the
- * superstate to handle an event. Applicable only to QMSMs.
- */</documentation>
- <code>(Q_RET_SUPER)</code>
- </operation>
- <!--${QEP-macros::QM_SUPER_SUB}-->
- <operation name="QM_SUPER_SUB" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to call in a QM submachine-handler when it designates the
- * host state to handle an event. Applicable only to subclasses of ::QMsm.
- */</documentation>
- <!--${QEP-macros::QM_SUPER_SUB::host_}-->
- <parameter name="host_" type="QStateHandler"/>
- <code>\
- ((Q_HSM_UPCAST(me))->temp.obj = (host_), Q_RET_SUPER_SUB)</code>
- </operation>
- <!--${QEP-macros::QM_STATE_NULL}-->
- <attribute name="QM_STATE_NULL" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to provide strictly-typed zero-state to use for submachines.
- *! Applicable to subclasses of ::QMsm.
- */</documentation>
- <code>((QMState *)0)</code>
- </attribute>
- </package>
- <!--${QEP}-->
- <package name="QEP" stereotype="0x05">
- <!--${QEP::QP_versionStr[8]}-->
- <attribute name="QP_versionStr[8]" type="char const" visibility="0x00" properties="0x00">
- <documentation>/*! the current QP version number string in ROM, based on #QP_VERSION_STR */</documentation>
- <code>= QP_VERSION_STR;</code>
- </attribute>
- <!--${QEP::QSignal}-->
- <attribute name="QSignal? (Q_SIGNAL_SIZE == 2U)" type="typedef uint16_t" visibility="0x04" properties="0x00">
- <documentation>/*! ::QSignal represents the signal of an event
- *
- * @details
- * The relationship between an event and a signal is as follows. A signal
- * in UML is the specification of an asynchronous stimulus that triggers
- * reactions, and as such is an essential part of an event. (The signal
- * conveys the type of the occurrence--what happened?) However, an event
- * can also contain additional quantitative information about the
- * occurrence in form of event parameters.
- */</documentation>
- </attribute>
- <!--${QEP::QSignal}-->
- <attribute name="QSignal? (Q_SIGNAL_SIZE == 1U)" type="typedef uint8_t" visibility="0x04" properties="0x00"/>
- <!--${QEP::QSignal}-->
- <attribute name="QSignal? (Q_SIGNAL_SIZE == 4U)" type="typedef uint32_t" visibility="0x04" properties="0x00"/>
- <!--${QEP::QEvt}-->
- <class name="QEvt">
- <documentation>/*! @brief Event class
- * @class QEvt
- *
- * @details
- * ::QEvt represents events without parameters and serves as the base class
- * for derivation of events with parameters.
- *
- * @trace
- * @tr{RQP001}, @tr{RQP004}, @tr{AQP210}
- *
- * @usage
- * The following example illustrates how to add an event parameter by
- * derivation of the ::QEvt class. Please note that the ::QEvt member
- * super is defined as the FIRST member of the derived struct.
- * @include qep_qevt.c
- */</documentation>
- <!--${QEP::QEvt::sig}-->
- <attribute name="sig" type="QSignal" visibility="0x00" properties="0x00">
- <documentation>/*! Signal of the event.
- * @public @memberof QEvt
- *
- * @trace
- * @tr{RQP002}
- */</documentation>
- </attribute>
- <!--${QEP::QEvt::poolId_}-->
- <attribute name="poolId_" type="uint8_t" visibility="0x02" properties="0x00">
- <documentation>/*! Pool ID (==0 for immutable event)
- * @private @memberof QEvt
- *
- * @trace
- * @tr{RQP003}
- */</documentation>
- </attribute>
- <!--${QEP::QEvt::refCtr_}-->
- <attribute name="refCtr_" type="uint8_t volatile" visibility="0x02" properties="0x00">
- <documentation>/*! Reference counter (for mutable events)
- * @private @memberof QEvt
- *
- * @trace
- * @tr{RQP003}
- */</documentation>
- </attribute>
- <!--${QEP::QEvt::ctor}-->
- <operation name="ctor?def Q_EVT_CTOR" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Custom event constructor
- * @public @memberof QEvt
- *
- * @note
- * Available only when the macro #Q_EVT_CTOR is defined
- *
- * @trace
- * @tr{RQP005}
- */</documentation>
- <!--${QEP::QEvt::ctor::sig}-->
- <parameter name="sig" type="enum_t const"/>
- </operation>
- </class>
- <!--${QEP::QStateRet}-->
- <attribute name="QStateRet" type="enum" visibility="0x04" properties="0x00">
- <documentation>/*! All possible values returned from state/action handlers
- *
- * @note
- * The order matters for algorithmic correctness.
- */</documentation>
- <code>{
- /* unhandled and need to "bubble up" */
- Q_RET_SUPER, /*!< event passed to superstate to handle */
- Q_RET_SUPER_SUB, /*!< event passed to submachine superstate */
- Q_RET_UNHANDLED, /*!< event unhandled due to a guard */
- /* handled and do not need to "bubble up" */
- Q_RET_HANDLED, /*!< event handled (internal transition) */
- Q_RET_IGNORED, /*!< event silently ignored (bubbled up to top) */
- /* entry/exit */
- Q_RET_ENTRY, /*!< state entry action executed */
- Q_RET_EXIT, /*!< state exit action executed */
- /* no side effects */
- Q_RET_NULL, /*!< return value without any effect */
- /* transitions need to execute transition-action table in ::QMsm */
- Q_RET_TRAN, /*!< regular transition */
- Q_RET_TRAN_INIT, /*!< initial transition in a state or submachine */
- Q_RET_TRAN_EP, /*!< entry-point transition into a submachine */
- /* transitions that additionally clobber me->state */
- Q_RET_TRAN_HIST, /*!< transition to history of a given state */
- Q_RET_TRAN_XP /*!< exit-point transition out of a submachine */
- };</code>
- </attribute>
- <!--${QEP::QState}-->
- <attribute name="QState" type="typedef enum QStateRet" visibility="0x04" properties="0x00">
- <documentation>/*! Type returned from state-handler functions */</documentation>
- </attribute>
- <!--${QEP::QStateHandler}-->
- <attribute name="QStateHandler" type="typedef QState (*" visibility="0x04" properties="0x00">
- <documentation>/*! Pointer to a state-handler function. */</documentation>
- <code>)(void * const me, QEvt const * const e);</code>
- </attribute>
- <!--${QEP::QActionHandler}-->
- <attribute name="QActionHandler" type="typedef QState (*" visibility="0x04" properties="0x00">
- <documentation>/*! Pointer to an action-handler function. */</documentation>
- <code>)(void * const me);</code>
- </attribute>
- <!--${QEP::QXThread}-->
- <attribute name="QXThread" type="struct" visibility="0x04" properties="0x00">
- <documentation>/* forward declaration */</documentation>
- </attribute>
- <!--${QEP::QXThreadHandler}-->
- <attribute name="QXThreadHandler" type="typedef void (*" visibility="0x04" properties="0x00">
- <documentation>/*! Pointer to an eXthended thread handler function */</documentation>
- <code>)(struct QXThread * const me);</code>
- </attribute>
- <!--${QEP::QMState}-->
- <attribute name="QMState" type="typedef struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief State object for the ::QMsm class (QM State Machine).
- *
- * @details
- * This class groups together the attributes of a ::QMsm state, such as the
- * parent state (state nesting), the associated state handler function and
- * the exit action handler function. These attributes are used inside the
- * QMsm_dispatch() and QMsm_init() functions.
- *
- * @trace
- * @tr{RQP104}
- *
- * @attention
- * The ::QMState class is only intended for the QM code generator and should
- * not be used in hand-crafted code.
- */</documentation>
- <code>{
- struct QMState const *superstate; /*!< superstate of this state */
- QStateHandler const stateHandler; /*!< state handler function */
- QActionHandler const entryAction; /*!< entry action handler function */
- QActionHandler const exitAction; /*!< exit action handler function */
- QActionHandler const initAction; /*!< init action handler function */
- } QMState;</code>
- </attribute>
- <!--${QEP::QMTranActTable}-->
- <attribute name="QMTranActTable" type="typedef struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief Transition-Action Table for the ::QMsm State Machine. */</documentation>
- <code>{
- QMState const *target; /*!< target of the transition */
- QActionHandler const act[1]; /*!< array of actions */
- } QMTranActTable;</code>
- </attribute>
- <!--${QEP::QHsmAttr}-->
- <attribute name="QHsmAttr" type="union" visibility="0x04" properties="0x00">
- <documentation>/*! @brief Attribute of for the ::QHsm class (Hierarchical State Machine).
- *
- * @details
- * This union represents possible values stored in the 'state' and 'temp'
- * attributes of the ::QHsm class.
- */</documentation>
- <code>{
- QStateHandler fun; /*!< @private pointer to a state-handler */
- QActionHandler act; /*!< @private pointer to an action-handler */
- QXThreadHandler thr; /*!< @private pointer to an thread-handler */
- QMTranActTable const *tatbl; /*!< @private transition-action table */
- struct QMState const *obj; /*!< @private pointer to QMState object */
- };</code>
- </attribute>
- <!--${QEP::QReservedSig}-->
- <attribute name="QReservedSig" type="enum" visibility="0x04" properties="0x00">
- <documentation>/*! Reserved signals by the HSM-style state machine
- * implementation strategy.
- */</documentation>
- <code>{
- Q_EMPTY_SIG, /*!< signal to execute the default case */
- Q_ENTRY_SIG, /*!< signal for coding entry actions */
- Q_EXIT_SIG, /*!< signal for coding exit actions */
- Q_INIT_SIG, /*!< signal for coding initial transitions */
- Q_USER_SIG /*!< offset for the user signals (QP Application) */
- };</code>
- </attribute>
- <!--${QEP::QHsm}-->
- <class name="QHsm">
- <documentation>/*! @brief Hierarchical State Machine class
- * @class QHsm
- *
- * @details
- * ::QHsm represents a Hierarchical State Machine (HSM) with full support for
- * hierarchical nesting of states, entry/exit actions, initial transitions,
- * and transitions to history in any composite state. This class is designed
- * for ease of manual coding of HSMs in C, but it is also supported by the
- * QM modeling tool.<br>
- *
- * ::QHsm is also the base class for the QMsm state machine, which provides
- * a superior efficiency, but requires the use of the QM modeling tool to
- * generate code.
- *
- * @note
- * ::QHsm is not intended to be instantiated directly, but rather serves as the
- * abstract base class for derivation of state machines in the QP application.
- *
- * @trace
- * @tr{RQP103}, @tr{AQP211}
- *
- * @usage
- * The following example illustrates how to derive a state machine class
- * from QHsm. Please note that the QHsm member `super` is defined as the
- * FIRST member of the derived class.
- * @include qep_qhsm.c
- */</documentation>
- <!--${QEP::QHsm::vptr}-->
- <attribute name="vptr" type="struct QHsmVtable const *" visibility="0x02" properties="0x00">
- <documentation>/*! Virtual pointer
- * @private @memberof QHsm
- *
- * @trace
- * @tr{RQP102}
- */</documentation>
- </attribute>
- <!--${QEP::QHsm::state}-->
- <attribute name="state" type="union QHsmAttr" visibility="0x01" properties="0x00">
- <documentation>/*! Current active state (state-variable).
- * @private @memberof QHsm
- */</documentation>
- </attribute>
- <!--${QEP::QHsm::temp}-->
- <attribute name="temp" type="union QHsmAttr" visibility="0x01" properties="0x00">
- <documentation>/*! Temporary: target/act-table, etc.
- * @private @memberof QHsm
- */</documentation>
- </attribute>
- <!--${QEP::QHsm::isIn}-->
- <operation name="isIn" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! Tests if a given state is part of the current active state
- * configuration in ::QHsm subclasses.
- * @public @memberof QHsm
- *
- * @details
- * Tests if a state machine derived from QHsm is-in a given state.
- *
- * @note For a HSM, to "be in a state" means also to be in a superstate of
- * of the state.
- *
- * @param[in] me current instance pointer (see @ref oop)
- * @param[in] state pointer to the state-handler function to be tested
- *
- * @returns
- *'true' if the HSM "is in" the `state` and 'false' otherwise
- *
- * @precondition{qep_hsm,600}
- * - the state configuration must be stable
- *
- * @trace
- * @tr{RQP103}, @tr{RQP120S}
- */
- /*! @public @memberof QHsm */</documentation>
- <!--${QEP::QHsm::isIn::state}-->
- <parameter name="state" type="QStateHandler const"/>
- <code>Q_REQUIRE_ID(600, me->temp.fun == me->state.fun);
- bool inState = false; /* assume that this HSM is not in 'state' */
- /* scan the state hierarchy bottom-up */
- QState r;
- do {
- /* do the states match? */
- if (me->temp.fun == state) {
- inState = true; /* 'true' means that match found */
- r = Q_RET_IGNORED; /* break out of the loop */
- }
- else {
- r = QHsm_reservedEvt_(me, me->temp.fun, Q_EMPTY_SIG);
- }
- } while (r != Q_RET_IGNORED); /* QHsm_top() state not reached */
- me->temp.fun = me->state.fun; /* restore the stable state configuration */
- return inState; /* return the status */</code>
- </operation>
- <!--${QEP::QHsm::state}-->
- <operation name="state" type="QStateHandler" visibility="0x00" properties="0x02">
- <documentation>/*! Obtain the current active state from a HSM (read only).
- * @public @memberof QHsm
- *
- * @param[in] me current instance pointer (see @ref oop)
- *
- * @returns the current active state of the QHsm class
- *
- * @note
- * This function is used in QM for auto-generating code for state history.
- */
- /*! @public @memberof QHsm */</documentation>
- <code>return me->state.fun;</code>
- </operation>
- <!--${QEP::QHsm::childState}-->
- <operation name="childState" type="QStateHandler" visibility="0x00" properties="0x00">
- <documentation>/*! Obtain the current active child state of a given parent in ::QHsm
- * @public @memberof QHsm
- *
- * @details
- * Finds the child state of the given `parent`, such that this child state
- * is an ancestor of the currently active state. The main purpose of this
- * function is to support **shallow history** transitions in state machines
- * derived from QHsm.
- *
- * @param[in] me current instance pointer (see @ref oop)
- * @param[in] parent pointer to the state-handler function
- *
- * @returns
- * the child of a given `parent` state, which is an ancestor of the current
- * active state. For the corner case when the currently active state is the
- * given `parent` state, function returns the `parent` state.
- *
- * @postcondition{qep_hsm,890}
- * - the child must be found
- *
- * @note
- * this function is designed to be called during state transitions, so it
- * does not necessarily start in a stable state configuration.
- * However, the function establishes stable state configuration upon exit.
- *
- * @trace
- * @tr{RQP103}, @tr{RQP120H}
- */
- /*! @public @memberof QHsm */</documentation>
- <!--${QEP::QHsm::childState::parent}-->
- <parameter name="parent" type="QStateHandler const"/>
- <code>QStateHandler child = me->state.fun; /* start with the current state */
- bool isFound = false; /* start with the child not found */
- /* establish stable state configuration */
- me->temp.fun = me->state.fun;
- QState r;
- do {
- /* is this the parent of the current child? */
- if (me->temp.fun == parent) {
- isFound = true; /* child is found */
- r = Q_RET_IGNORED; /* break out of the loop */
- }
- else {
- child = me->temp.fun;
- r = QHsm_reservedEvt_(me, me->temp.fun, Q_EMPTY_SIG);
- }
- } while (r != Q_RET_IGNORED); /* QHsm_top() state not reached */
- me->temp.fun = me->state.fun; /* establish stable state configuration */
- Q_ENSURE_ID(890, isFound);
- #ifdef Q_NASSERT
- Q_UNUSED_PAR(isFound);
- #endif
- return child; /* return the child */</code>
- </operation>
- <!--${QEP::QHsm::ctor}-->
- <operation name="ctor" type="void" visibility="0x01" properties="0x00">
- <documentation>/*! Protected "constructor" of ::QHsm
- * @protected @memberof QHsm
- *
- * @details
- * Performs the first step of HSM initialization by assigning the initial
- * pseudostate to the currently active state of the state machine.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] initial pointer to the top-most initial state-handler
- * function in the derived state machine
- *
- * @note Must be called only by the constructors of the derived state
- * machines.
- *
- * @note Must be called only ONCE before QHSM_INIT().
- *
- * @usage
- * The following example illustrates how to invoke QHsm_ctor() in the
- * "constructor" of a derived state machine:
- * @include qep_qhsm_ctor.c
- *
- * @trace
- * @tr{RQP103}
- */
- /*! @protected @memberof QHsm */</documentation>
- <!--${QEP::QHsm::ctor::initial}-->
- <parameter name="initial" type="QStateHandler const"/>
- <code>static struct QHsmVtable const vtable = { /* QHsm virtual table */
- &QHsm_init_,
- &QHsm_dispatch_
- #ifdef Q_SPY
- ,&QHsm_getStateHandler_
- #endif
- };
- me->vptr = &vtable;
- me->state.fun = Q_STATE_CAST(&QHsm_top);
- me->temp.fun = initial;</code>
- </operation>
- <!--${QEP::QHsm::top}-->
- <operation name="top" type="QState" visibility="0x01" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! The top-state of QHsm.
- * @protected @memberof QHsm
- *
- * @details
- * QHsm_top() is the ultimate root of state hierarchy in all HSMs derived
- * from ::QHsm.
- *
- * @param[in] me current instance pointer (see @ref oop)
- * @param[in] e pointer to the event to be dispatched to the FSM
- *
- * @returns
- * Always returns ::Q_RET_IGNORED, which means that the top state ignores
- * all events.
- *
- * @note The parameters to this state handler are not used. They are provided
- * for conformance with the state-handler function signature ::QStateHandler.
- *
- * @trace
- * @tr{RQP103}, @tr{RQP120T}
- */
- /*! @protected @memberof QHsm */</documentation>
- <!--${QEP::QHsm::top::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <code>Q_UNUSED_PAR(me);
- Q_UNUSED_PAR(e);
- return Q_RET_IGNORED; /* the top state ignores all events */</code>
- </operation>
- <!--${QEP::QHsm::init_}-->
- <operation name="init_" type="void" visibility="0x01" properties="0x00">
- <documentation>/*! Implementation of the top-most initial tran. in ::QHsm.
- * @protected @memberof QHsm
- *
- * @details
- * Executes the top-most initial transition in a HSM.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] e pointer to an extra parameter (might be NULL)
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- *
- * @precondition{qep_hsm,200}
- * - the virtual pointer must be initialized,
- * - the top-most initial transition must be initialized,
- * - the initial transition must not be taken yet.
- *
- * @note Must be called only ONCE after the QHsm_ctor().
- *
- * @trace
- * @tr{RQP103}, @tr{RQP120I}, @tr{RQP120D}
- */
- /*! @protected @memberof QHsm */</documentation>
- <!--${QEP::QHsm::init_::e}-->
- <parameter name="e" type="void const * const"/>
- <!--${QEP::QHsm::init_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifdef Q_SPY
- if ((QS_priv_.flags & 0x01U) == 0U) {
- QS_priv_.flags |= 0x01U;
- QS_FUN_DICTIONARY(&QHsm_top);
- }
- #else
- Q_UNUSED_PAR(qs_id);
- #endif
- QStateHandler t = me->state.fun;
- Q_REQUIRE_ID(200, (me->vptr != (struct QHsmVtable *)0)
- && (me->temp.fun != Q_STATE_CAST(0))
- && (t == Q_STATE_CAST(&QHsm_top)));
- /* execute the top-most initial tran. */
- QState r = (*me->temp.fun)(me, Q_EVT_CAST(QEvt));
- /* the top-most initial transition must be taken */
- Q_ASSERT_ID(210, r == Q_RET_TRAN);
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(t); /* the source state */
- QS_FUN_PRE_(me->temp.fun); /* the target of the initial transition */
- QS_END_PRE_()
- /* drill down into the state hierarchy with initial transitions... */
- do {
- QStateHandler path[QHSM_MAX_NEST_DEPTH_]; /* tran entry path array */
- int_fast8_t ip = 0; /* tran entry path index */
- path[0] = me->temp.fun;
- (void)QHsm_reservedEvt_(me, me->temp.fun, Q_EMPTY_SIG);
- while (me->temp.fun != t) {
- ++ip;
- Q_ASSERT_ID(220, ip < QHSM_MAX_NEST_DEPTH_);
- path[ip] = me->temp.fun;
- (void)QHsm_reservedEvt_(me, me->temp.fun, Q_EMPTY_SIG);
- }
- me->temp.fun = path[0];
- /* nested initial transition, drill into the target hierarchy... */
- do {
- QHsm_state_entry_(me, path[ip], qs_id); /* enter path[ip] */
- --ip;
- } while (ip >= 0);
- t = path[0]; /* current state becomes the new source */
- r = QHsm_reservedEvt_(me, t, Q_INIT_SIG); /* execute initial transition */
- #ifdef Q_SPY
- if (r == Q_RET_TRAN) {
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(t); /* the source state */
- QS_FUN_PRE_(me->temp.fun); /* target of the initial tran. */
- QS_END_PRE_()
- }
- #endif /* Q_SPY */
- } while (r == Q_RET_TRAN);
- QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(t); /* the new active state */
- QS_END_PRE_()
- me->state.fun = t; /* change the current active state */
- me->temp.fun = t; /* mark the configuration as stable */</code>
- </operation>
- <!--${QEP::QHsm::dispatch_}-->
- <operation name="dispatch_" type="void" visibility="0x01" properties="0x00">
- <documentation>/*! Implementation of dispatching events to a ::QHsm
- * @protected @memberof QHsm
- *
- * @details
- * Dispatches an event for processing to a hierarchical state machine (HSM).
- * The processing of an event represents one run-to-completion (RTC) step.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] e pointer to the event to be dispatched to the HSM
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- *
- * @precondition{qep_hsm,400}
- * - the current state must be initialized and
- * - the state configuration must be stable
- *
- * @note
- * This function should be called only via the virtual table (see
- * QHSM_DISPATCH()) and should NOT be called directly in the applications.
- *
- * @trace
- * @tr{RQP103}, @tr{RQP120A}, @tr{RQP120B}, @tr{RQP120C},
- * @tr{RQP120D}, @tr{RQP120E}, @tr{RQP120E}, @tr{RQP120C},
- * @tr{RQP120B}
- */
- /*! @protected @memberof QHsm */</documentation>
- <!--${QEP::QHsm::dispatch_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QEP::QHsm::dispatch_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- QStateHandler t = me->state.fun;
- QS_CRIT_STAT_
- Q_REQUIRE_ID(400, (t != Q_STATE_CAST(0))
- && (t == me->temp.fun));
- QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(t); /* the current state */
- QS_END_PRE_()
- QStateHandler s;
- QState r;
- /* process the event hierarchically... */
- do {
- s = me->temp.fun;
- r = (*s)(me, e); /* invoke state handler s */
- if (r == Q_RET_UNHANDLED) { /* unhandled due to a guard? */
- QS_BEGIN_PRE_(QS_QEP_UNHANDLED, qs_id)
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(s); /* the current state */
- QS_END_PRE_()
- r = QHsm_reservedEvt_(me, s, Q_EMPTY_SIG); /* find superstate of s */
- }
- } while (r == Q_RET_SUPER);
- /* regular transition taken? */
- if (r >= Q_RET_TRAN) {
- QStateHandler path[QHSM_MAX_NEST_DEPTH_];
- path[0] = me->temp.fun; /* save the target of the transition */
- path[1] = t;
- path[2] = s;
- /* exit current state to transition source s... */
- for (; t != s; t = me->temp.fun) {
- /* exit from t handled? */
- if (QHsm_state_exit_(me, t, qs_id)) {
- /* find superstate of t */
- (void)QHsm_reservedEvt_(me, t, Q_EMPTY_SIG);
- }
- }
- int_fast8_t ip = QHsm_tran_(me, path, qs_id); /* the HSM transition */
- #ifdef Q_SPY
- if (r == Q_RET_TRAN_HIST) {
- QS_BEGIN_PRE_(QS_QEP_TRAN_HIST, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(t); /* the source of the transition */
- QS_FUN_PRE_(path[0]); /* the target of tran. to history */
- QS_END_PRE_()
- }
- #endif /* Q_SPY */
- /* execute state entry actions in the desired order... */
- for (; ip >= 0; --ip) {
- QHsm_state_entry_(me, path[ip], qs_id); /* enter path[ip] */
- }
- t = path[0]; /* stick the target into register */
- me->temp.fun = t; /* update the next state */
- /* while nested initial transition... */
- /*! @tr{RQP120I} */
- while (QHsm_reservedEvt_(me, t, Q_INIT_SIG) == Q_RET_TRAN) {
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(t); /* the source (pseudo)state */
- QS_FUN_PRE_(me->temp.fun); /* the target of the tran. */
- QS_END_PRE_()
- ip = 0;
- path[0] = me->temp.fun;
- /* find superstate */
- (void)QHsm_reservedEvt_(me, me->temp.fun, Q_EMPTY_SIG);
- while (me->temp.fun != t) {
- ++ip;
- path[ip] = me->temp.fun;
- /* find superstate */
- (void)QHsm_reservedEvt_(me, me->temp.fun, Q_EMPTY_SIG);
- }
- me->temp.fun = path[0];
- /* entry path must not overflow */
- Q_ASSERT_ID(410, ip < QHSM_MAX_NEST_DEPTH_);
- /* retrace the entry path in reverse (correct) order... */
- do {
- QHsm_state_entry_(me, path[ip], qs_id); /* enter path[ip] */
- --ip;
- } while (ip >= 0);
- t = path[0]; /* current state becomes the new source */
- }
- QS_BEGIN_PRE_(QS_QEP_TRAN, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(s); /* the source of the transition */
- QS_FUN_PRE_(t); /* the new active state */
- QS_END_PRE_()
- }
- #ifdef Q_SPY
- else if (r == Q_RET_HANDLED) {
- QS_BEGIN_PRE_(QS_QEP_INTERN_TRAN, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(s); /* the source state */
- QS_END_PRE_()
- }
- else {
- QS_BEGIN_PRE_(QS_QEP_IGNORED, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(me->state.fun); /* the current state */
- QS_END_PRE_()
- }
- #endif /* Q_SPY */
- me->state.fun = t; /* change the current active state */
- me->temp.fun = t; /* mark the configuration as stable */</code>
- </operation>
- <!--${QEP::QHsm::getStateHandler_}-->
- <operation name="getStateHandler_?def Q_SPY" type="QStateHandler" visibility="0x02" properties="0x00">
- <documentation>/*! Implementation of getting the state handler in a ::QHsm subclass
- * @private @memberof QHsm
- */
- /*! @private @memberof QHsm */</documentation>
- <code>return me->state.fun;</code>
- </operation>
- <!--${QEP::QHsm::tran_}-->
- <operation name="tran_" type="int_fast8_t" visibility="0x02" properties="0x00">
- <documentation>/*! Helper function to execute transition sequence in a hierarchical state
- * machine (HSM).
- *
- * @param[in,out] path array of pointers to state-handler functions
- * to execute the entry actions
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- *
- * @returns
- * the depth of the entry path stored in the `path` parameter.
- *
- * @trace
- * @tr{RQP103}, @tr{RQP120E}, @tr{RQP120F}
- */
- /*! @private @memberof QHsm */</documentation>
- <!--${QEP::QHsm::tran_::path}-->
- <parameter name="path" type="QStateHandler * const"/>
- <!--${QEP::QHsm::tran_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- int_fast8_t ip = -1; /* transition entry path index */
- QStateHandler t = path[0];
- QStateHandler const s = path[2];
- /* (a) check source==target (transition to self)... */
- if (s == t) {
- (void)QHsm_state_exit_(me, s, qs_id); /* exit source */
- ip = 0; /* enter the target */
- }
- else {
- /* find superstate of target */
- (void)QHsm_reservedEvt_(me, t, Q_EMPTY_SIG);
- t = me->temp.fun;
- /* (b) check source==target->super... */
- if (s == t) {
- ip = 0; /* enter the target */
- }
- else {
- /* find superstate of src */
- (void)QHsm_reservedEvt_(me, s, Q_EMPTY_SIG);
- /* (c) check source->super==target->super... */
- if (me->temp.fun == t) {
- (void)QHsm_state_exit_(me, s, qs_id); /* exit source */
- ip = 0; /* enter the target */
- }
- else {
- /* (d) check source->super==target... */
- if (me->temp.fun == path[0]) {
- (void)QHsm_state_exit_(me, s, qs_id); /* exit source */
- }
- else {
- /* (e) check rest of source==target->super->super..
- * and store the entry path along the way
- */
- int_fast8_t iq = 0; /* indicate that LCA not found */
- ip = 1; /* enter target and its superstate */
- path[1] = t; /* save the superstate of target */
- t = me->temp.fun; /* save source->super */
- /* find target->super->super... */
- QState r = QHsm_reservedEvt_(me, path[1], Q_EMPTY_SIG);
- while (r == Q_RET_SUPER) {
- ++ip;
- path[ip] = me->temp.fun; /* store the entry path */
- if (me->temp.fun == s) { /* is it the source? */
- iq = 1; /* indicate that LCA found */
- /* entry path must not overflow */
- Q_ASSERT_ID(510,
- ip < QHSM_MAX_NEST_DEPTH_);
- --ip; /* do not enter the source */
- r = Q_RET_HANDLED; /* terminate loop */
- }
- /* it is not the source, keep going up */
- else {
- r = QHsm_reservedEvt_(me, me->temp.fun,
- Q_EMPTY_SIG);
- }
- }
- /* the LCA not found yet? */
- if (iq == 0) {
- /* entry path must not overflow */
- Q_ASSERT_ID(520, ip < QHSM_MAX_NEST_DEPTH_);
- /* exit source */
- (void)QHsm_state_exit_(me, s, qs_id);
- /* (f) check the rest of source->super
- * == target->super->super...
- */
- iq = ip;
- r = Q_RET_IGNORED; /* LCA NOT found */
- do {
- if (t == path[iq]) { /* is this the LCA? */
- r = Q_RET_HANDLED; /* LCA found */
- ip = iq - 1; /* do not enter LCA */
- iq = -1; /* cause termintion of the loop */
- }
- else {
- --iq; /* try lower superstate of target */
- }
- } while (iq >= 0);
- /* LCA not found? */
- if (r != Q_RET_HANDLED) {
- /* (g) check each source->super->...
- * for each target->super...
- */
- r = Q_RET_IGNORED; /* keep looping */
- do {
- /* exit from t handled? */
- if (QHsm_state_exit_(me, t, qs_id)) {
- /* find superstate of t */
- (void)QHsm_reservedEvt_(me, t, Q_EMPTY_SIG);
- }
- t = me->temp.fun; /* set to super of t */
- iq = ip;
- do {
- /* is this LCA? */
- if (t == path[iq]) {
- /* do not enter LCA */
- ip = (int_fast8_t)(iq - 1);
- iq = -1; /* break out of inner loop */
- /* break out of outer loop */
- r = Q_RET_HANDLED;
- }
- else {
- --iq;
- }
- } while (iq >= 0);
- } while (r != Q_RET_HANDLED);
- }
- }
- }
- }
- }
- }
- return ip;</code>
- </operation>
- <!--${QEP::QHsm::state_entry_}-->
- <operation name="state_entry_" type="void" visibility="0x02" properties="0x00">
- <documentation>/*! Helper function to execute entry into a given state in a
- * hierarchical state machine (HSM).
- * @private @memberof QHsm
- *
- * @param[in] state state handler function
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- */
- /*! @private @memberof QHsm */</documentation>
- <!--${QEP::QHsm::state_entry_::state}-->
- <parameter name="state" type="QStateHandler const"/>
- <!--${QEP::QHsm::state_entry_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifdef Q_SPY
- if ((*state)(me, &l_reservedEvt_[Q_ENTRY_SIG]) == Q_RET_HANDLED) {
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, qs_id)
- QS_OBJ_PRE_(me);
- QS_FUN_PRE_(state);
- QS_END_PRE_()
- }
- #else
- Q_UNUSED_PAR(qs_id);
- (void)(*state)(me, &l_reservedEvt_[Q_ENTRY_SIG]);
- #endif /* Q_SPY */</code>
- </operation>
- <!--${QEP::QHsm::state_exit_}-->
- <operation name="state_exit_" type="bool" visibility="0x02" properties="0x00">
- <documentation>/*! Helper function to execute exit from a given state in a
- * hierarchical state machine (HSM).
- * @private @memberof QHsm
- *
- * @param[in] state state handler function
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- *
- * @returns
- * 'true' if the exit action has been found in the state and
- * 'flase' otherwise.
- */
- /*! @private @memberof QHsm */</documentation>
- <!--${QEP::QHsm::state_exit_::state}-->
- <parameter name="state" type="QStateHandler const"/>
- <!--${QEP::QHsm::state_exit_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifdef Q_SPY
- bool isHandled;
- if ((*state)(me, &l_reservedEvt_[Q_EXIT_SIG]) == Q_RET_HANDLED) {
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_STATE_EXIT, qs_id)
- QS_OBJ_PRE_(me);
- QS_FUN_PRE_(state);
- QS_END_PRE_()
- isHandled = true;
- }
- else {
- isHandled = false;
- }
- return isHandled;
- #else
- Q_UNUSED_PAR(qs_id);
- return (*state)(me, &l_reservedEvt_[Q_EXIT_SIG]) == Q_RET_HANDLED;
- #endif /* Q_SPY */</code>
- </operation>
- </class>
- <!--${QEP::QHsmVtable}-->
- <attribute name="QHsmVtable" type="struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief Virtual table for the ::QHsm class.
- *
- * @trace
- * @tr{RQP102}
- */</documentation>
- <code>{
- /*! Triggers the top-most initial transition in the HSM. */
- void (*init)(QHsm * const me, void const * const e,
- uint_fast8_t const qs_id);
- /*! Dispatches an event to the HSM. */
- void (*dispatch)(QHsm * const me, QEvt const * const e,
- uint_fast8_t const qs_id);
- #ifdef Q_SPY
- /*! Get the current state handler of the HSM. */
- QStateHandler (*getStateHandler)(QHsm * const me);
- #endif /* Q_SPY */
- };</code>
- </attribute>
- <!--${QEP::QMsm}-->
- <class name="QMsm" superclass="QEP::QHsm">
- <documentation>/*! @brief QM state machine implementation strategy
- * @class QMsm
- * @extends QHsm
- *
- * @details
- * QMsm (QM State Machine) provides a more efficient state machine
- * implementation strategy than ::QHsm, but requires the use of the QM
- * modeling tool, but are the fastest and need the least run-time
- * support (the smallest event-processor taking up the least code space).
- *
- * @note
- * QMsm is not intended to be instantiated directly, but rather serves
- * as the abstrace base class for derivation of state machines in the
- * application code.
- *
- * @trace
- * @tr{RQP104}
- *
- * @usage
- * The following example illustrates how to derive a state machine class
- * from QMsm. Please note that the QMsm member `super` is defined
- * as the *first* member of the derived struct.
- * @include qep_qmsm.c
- */</documentation>
- <!--${QEP::QMsm::isInState}-->
- <operation name="isInState" type="bool" visibility="0x00" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! Tests if a given state is part of the current active state
- * configuration in a MSM.
- * @public @memberof QMsm
- *
- * @details
- * Tests if a state machine derived from QMsm is-in a given state.
- *
- * @note
- * For a MSM, to "be-in" a state means also to "be-in" a superstate of
- * of the state.
- *
- * @param[in] me current instance pointer (see @ref oop)
- * @param[in] state pointer to the QMState object that corresponds to the
- * tested state.
- * @returns
- * 'true' if the MSM "is in" the `state` and 'false' otherwise
- */
- /*! @public @memberof QMsm */</documentation>
- <!--${QEP::QMsm::isInState::state}-->
- <parameter name="state" type="QMState const * const"/>
- <code>bool inState = false; /* assume that this MSM is not in 'state' */
- for (QMState const *s = me->super.state.obj;
- s != (QMState *)0;
- s = s->superstate)
- {
- if (s == state) {
- inState = true; /* match found, return 'true' */
- break;
- }
- }
- return inState;</code>
- </operation>
- <!--${QEP::QMsm::stateObj}-->
- <operation name="stateObj" type="QMState const *" visibility="0x00" properties="0x01">
- <documentation>/*! Obtain the current active state from a MSM (read only)
- * @public @memberof QMsm
- *
- * @param[in] me current instance pointer (see @ref oop)
- *
- * @returns the current active state-object
- *
- * @note
- * This function is used in QM for auto-generating code for state history
- */
- /*! @public @memberof QMsm */</documentation>
- <!--${QEP::QMsm::stateObj::me}-->
- <parameter name="me" type="QHsm const * const"/>
- <code>return me->state.obj;</code>
- </operation>
- <!--${QEP::QMsm::childStateObj}-->
- <operation name="childStateObj" type="QMState const *" visibility="0x00" properties="0x01">
- <documentation>/*! Obtain the current active child state of a given parent in ::QMsm
- * @public @memberof QMsm
- *
- * @details
- * Finds the child state of the given @c parent, such that this child state
- * is an ancestor of the currently active state. The main purpose of this
- * function is to support **shallow history** transitions in state machines
- * derived from QMsm.
- *
- * @param[in] me current instance pointer (see @ref oop)
- * @param[in] parent pointer to the state-handler object
- *
- * @returns
- * the child of a given @c parent state, which is an ancestor of
- * the currently active state. For the corner case when the currently active
- * state is the given @c parent state, function returns the @c parent state.
- *
- * @postcondition{qep_msm,890}
- * - the child must be found
- *
- * @sa QMsm_childStateObj()
- */
- /*! @public @memberof QMsm */</documentation>
- <!--${QEP::QMsm::childStateObj::me}-->
- <parameter name="me" type="QHsm const * const"/>
- <!--${QEP::QMsm::childStateObj::parent}-->
- <parameter name="parent" type="QMState const * const"/>
- <code>QMState const *child = me->state.obj;
- bool isFound = false; /* start with the child not found */
- QMState const *s;
- for (s = me->state.obj; s != (QMState *)0; s = s->superstate) {
- if (s == parent) {
- isFound = true; /* child is found */
- break;
- }
- else {
- child = s;
- }
- }
- if (!isFound) { /* still not found? */
- for (s = me->temp.obj; s != (QMState *)0; s = s->superstate) {
- if (s == parent) {
- isFound = true; /* child is found */
- break;
- }
- else {
- child = s;
- }
- }
- }
- Q_ENSURE_ID(890, isFound);
- #ifdef Q_NASSERT
- Q_UNUSED_PAR(isFound);
- #endif
- return child; /* return the child */</code>
- </operation>
- <!--${QEP::QMsm::ctor}-->
- <operation name="ctor" type="void" visibility="0x01" properties="0x00">
- <documentation>/*! Constructor of ::QMsm
- * @protected @memberof QMsm
- *
- * @details
- * Performs the first step of QMsm initialization by assigning the initial
- * pseudostate to the currently active state of the state machine.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] initial the top-most initial transition for the MSM.
- *
- * @note
- * Must be called only ONCE before QHSM_INIT().
- *
- * @note
- * QMsm inherits QHsm, so by the @ref oop convention it should call the
- * constructor of the superclass, i.e., QHsm_ctor(). However, this would pull
- * in the QHsmVtable, which in turn will pull in the code for QHsm_init_() and
- * QHsm_dispatch_() implemetations. To avoid this code size penalty, in case
- * ::QHsm is not used in a given project, the QMsm_ctor() performs direct
- * intitialization of the Vtable, which avoids pulling in the code for QMsm.
- *
- * @usage
- * The following example illustrates how to invoke QMsm_ctor() in the
- * "constructor" of a derived state machine:
- * @include qep_qmsm_ctor.c
- */
- /*! @protected @memberof QMsm */</documentation>
- <!--${QEP::QMsm::ctor::initial}-->
- <parameter name="initial" type="QStateHandler const"/>
- <code>static struct QHsmVtable const vtable = { /* QHsm virtual table */
- &QMsm_init_,
- &QMsm_dispatch_
- #ifdef Q_SPY
- ,&QMsm_getStateHandler_
- #endif
- };
- /* do not call the QHsm_ctor() here */
- me->super.vptr = &vtable;
- me->super.state.obj = &l_msm_top_s; /* the current state (top) */
- me->super.temp.fun = initial; /* the initial transition handler */</code>
- </operation>
- <!--${QEP::QMsm::init_}-->
- <operation name="init_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Implementation of the top-most initial tran. in ::QMsm.
- * @private @memberof QMsm
- *
- * @details
- * Executes the top-most initial transition in a MSM.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] e pointer to an extra parameter (might be NULL)
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- *
- * @precondition{qep_msm,200}
- * - the virtual pointer must be initialized,
- * - the top-most initial transition must be initialized,
- * - the initial transition must not be taken yet.
- *
- * @note
- * This function should be called only via the virtual table (see
- * QHSM_INIT()) and should NOT be called directly in the applications.
- */
- /*! @private @memberof QMsm */</documentation>
- <!--${QEP::QMsm::init_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QEP::QMsm::init_::e}-->
- <parameter name="e" type="void const * const"/>
- <!--${QEP::QMsm::init_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- Q_REQUIRE_ID(200, (me->vptr != (struct QHsmVtable *)0)
- && (me->temp.fun != Q_STATE_CAST(0))
- && (me->state.obj == &l_msm_top_s));
- /* execute the top-most initial tran. */
- QState r = (*me->temp.fun)(me, Q_EVT_CAST(QEvt));
- /* the top-most initial transition must be taken */
- Q_ASSERT_ID(210, r == Q_RET_TRAN_INIT);
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(me->state.obj->stateHandler); /* source state */
- QS_FUN_PRE_(me->temp.tatbl->target->stateHandler); /* target state */
- QS_END_PRE_()
- /* set state to the last tran. target */
- me->state.obj = me->temp.tatbl->target;
- /* drill down into the state hierarchy with initial transitions... */
- /* execute the tran. table */
- do {
- r = QMsm_execTatbl_(me, me->temp.tatbl, qs_id);
- } while (r >= Q_RET_TRAN_INIT);
- QS_BEGIN_PRE_(QS_QEP_INIT_TRAN, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(me->state.obj->stateHandler); /* the new current state */
- QS_END_PRE_()</code>
- </operation>
- <!--${QEP::QMsm::dispatch_}-->
- <operation name="dispatch_" type="void" visibility="0x02" properties="0x01">
- <documentation>/*! Implementation of dispatching events to a ::QMsm
- * @private @memberof QMsm
- *
- * @details
- * Dispatches an event for processing to a meta state machine (MSM).
- * The processing of an event represents one run-to-completion (RTC) step.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] e pointer to the event to be dispatched to the MSM
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- *
- * @precondition{qep_msm,300}
- * - current state must be initialized
- *
- * @note
- * This function should be called only via the virtual table (see
- * QHSM_DISPATCH()) and should NOT be called directly in the applications.
- */
- /*! @private @memberof QMsm */</documentation>
- <!--${QEP::QMsm::dispatch_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QEP::QMsm::dispatch_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QEP::QMsm::dispatch_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- QMState const *s = me->state.obj; /* store the current state */
- QMState const *t = s;
- Q_REQUIRE_ID(300, s != (QMState *)0);
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(s->stateHandler); /* the current state handler */
- QS_END_PRE_()
- /* scan the state hierarchy up to the top state... */
- QState r;
- do {
- r = (*t->stateHandler)(me, e); /* call state handler function */
- /* event handled? (the most frequent case) */
- if (r >= Q_RET_HANDLED) {
- break; /* done scanning the state hierarchy */
- }
- /* event unhandled and passed to the superstate? */
- else if (r == Q_RET_SUPER) {
- t = t->superstate; /* advance to the superstate */
- }
- /* event unhandled and passed to a submachine superstate? */
- else if (r == Q_RET_SUPER_SUB) {
- t = me->temp.obj; /* current host state of the submachie */
- }
- /* event unhandled due to a guard? */
- else if (r == Q_RET_UNHANDLED) {
- QS_BEGIN_PRE_(QS_QEP_UNHANDLED, qs_id)
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(t->stateHandler); /* the current state */
- QS_END_PRE_()
- t = t->superstate; /* advance to the superstate */
- }
- else {
- /* no other return value should be produced */
- Q_ERROR_ID(310);
- }
- } while (t != (QMState *)0);
- /* any kind of transition taken? */
- if (r >= Q_RET_TRAN) {
- #ifdef Q_SPY
- QMState const * const ts = t; /* transition source for QS tracing */
- /* the transition source state must not be NULL */
- Q_ASSERT_ID(320, ts != (QMState *)0);
- #endif /* Q_SPY */
- do {
- /* save the transition-action table before it gets clobbered */
- struct QMTranActTable const * const tatbl = me->temp.tatbl;
- union QHsmAttr tmp; /* temporary to save intermediate values */
- /* was TRAN, TRAN_INIT, or TRAN_EP taken? */
- if (r <= Q_RET_TRAN_EP) {
- me->temp.obj = (QMState *)0; /* clear */
- QMsm_exitToTranSource_(me, s, t, qs_id);
- r = QMsm_execTatbl_(me, tatbl, qs_id);
- s = me->state.obj;
- }
- /* was a transition segment to history taken? */
- else if (r == Q_RET_TRAN_HIST) {
- tmp.obj = me->state.obj; /* save history */
- me->state.obj = s; /* restore the original state */
- QMsm_exitToTranSource_(me, s, t, qs_id);
- (void)QMsm_execTatbl_(me, tatbl, qs_id);
- r = QMsm_enterHistory_(me, tmp.obj, qs_id);
- s = me->state.obj;
- }
- /* was a transition segment to an exit point taken? */
- else if (r == Q_RET_TRAN_XP) {
- tmp.act = me->state.act; /* save XP action */
- me->state.obj = s; /* restore the original state */
- r = (*tmp.act)(me); /* execute the XP action */
- if (r == Q_RET_TRAN) { /* XP -> TRAN ? */
- tmp.tatbl = me->temp.tatbl; /* save me->temp */
- QMsm_exitToTranSource_(me, s, t, qs_id);
- /* take the tran-to-XP segment inside submachine */
- (void)QMsm_execTatbl_(me, tatbl, qs_id);
- s = me->state.obj;
- #ifdef Q_SPY
- me->temp.tatbl = tmp.tatbl; /* restore me->temp */
- #endif /* Q_SPY */
- }
- else if (r == Q_RET_TRAN_HIST) { /* XP -> HIST ? */
- tmp.obj = me->state.obj; /* save the history */
- me->state.obj = s; /* restore the original state */
- s = me->temp.obj; /* save me->temp */
- QMsm_exitToTranSource_(me, me->state.obj, t, qs_id);
- /* take the tran-to-XP segment inside submachine */
- (void)QMsm_execTatbl_(me, tatbl, qs_id);
- #ifdef Q_SPY
- me->temp.obj = s; /* restore me->temp */
- #endif /* Q_SPY */
- s = me->state.obj;
- me->state.obj = tmp.obj; /* restore the history */
- }
- else {
- /* TRAN_XP must NOT be followed by any other tran type */
- Q_ASSERT_ID(330, r < Q_RET_TRAN);
- }
- }
- else {
- /* no other return value should be produced */
- Q_ERROR_ID(340);
- }
- t = s; /* set target to the current state */
- } while (r >= Q_RET_TRAN);
- QS_BEGIN_PRE_(QS_QEP_TRAN, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(ts->stateHandler); /* the transition source */
- QS_FUN_PRE_(s->stateHandler); /* the new active state */
- QS_END_PRE_()
- }
- #ifdef Q_SPY
- /* was the event handled? */
- else if (r == Q_RET_HANDLED) {
- /* internal tran. source can't be NULL */
- Q_ASSERT_ID(340, t != (QMState *)0);
- QS_BEGIN_PRE_(QS_QEP_INTERN_TRAN, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(t->stateHandler); /* the source state */
- QS_END_PRE_()
- }
- /* event bubbled to the 'top' state? */
- else if (t == (QMState *)0) {
- QS_BEGIN_PRE_(QS_QEP_IGNORED, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(s->stateHandler); /* the current state */
- QS_END_PRE_()
- }
- #endif /* Q_SPY */
- else {
- /* empty */
- }</code>
- </operation>
- <!--${QEP::QMsm::getStateHandler_}-->
- <operation name="getStateHandler_?def Q_SPY" type="QStateHandler" visibility="0x00" properties="0x01">
- <documentation>/*! Implementation of getting the state handler in a ::QMsm subclass
- * @public @memberof QMsm
- */
- /*! @public @memberof QMsm */</documentation>
- <!--${QEP::QMsm::getStateHandler_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <code>return me->state.obj->stateHandler;</code>
- </operation>
- <!--${QEP::QMsm::execTatbl_}-->
- <operation name="execTatbl_" type="QState" visibility="0x02" properties="0x01">
- <documentation>/*! Execute transition-action table
- * @private @memberof QMsm
- *
- * @details
- * Helper function to execute transition sequence in a transition-action table.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] tatbl pointer to the transition-action table
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- *
- * @returns
- * status of the last action from the transition-action table.
- *
- * @note
- * This function is for internal use inside the QEP event processor and
- * should **not** be called directly from the applications.
- */
- /*! @private @memberof QMsm */</documentation>
- <!--${QEP::QMsm::execTatbl_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QEP::QMsm::execTatbl_::tatbl}-->
- <parameter name="tatbl" type="QMTranActTable const * const"/>
- <!--${QEP::QMsm::execTatbl_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- QState r = Q_RET_NULL;
- QS_CRIT_STAT_
- /*! @pre the transition-action table pointer must not be NULL */
- Q_REQUIRE_ID(400, tatbl != (struct QMTranActTable *)0);
- for (QActionHandler const *a = &tatbl->act[0];
- *a != Q_ACTION_CAST(0);
- ++a)
- {
- r = (*(*a))(me); /* call the action through the 'a' pointer */
- #ifdef Q_SPY
- if (r == Q_RET_ENTRY) {
- QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(me->temp.obj->stateHandler);/*entered state */
- QS_END_PRE_()
- }
- else if (r == Q_RET_EXIT) {
- QS_BEGIN_PRE_(QS_QEP_STATE_EXIT, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(me->temp.obj->stateHandler); /* exited state */
- QS_END_PRE_()
- }
- else if (r == Q_RET_TRAN_INIT) {
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(tatbl->target->stateHandler); /* source */
- QS_FUN_PRE_(me->temp.tatbl->target->stateHandler);/* target */
- QS_END_PRE_()
- }
- else if (r == Q_RET_TRAN_EP) {
- QS_BEGIN_PRE_(QS_QEP_TRAN_EP, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(tatbl->target->stateHandler); /* source */
- QS_FUN_PRE_(me->temp.tatbl->target->stateHandler);/* target */
- QS_END_PRE_()
- }
- else if (r == Q_RET_TRAN_XP) {
- QS_BEGIN_PRE_(QS_QEP_TRAN_XP, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(tatbl->target->stateHandler); /* source */
- QS_FUN_PRE_(me->temp.tatbl->target->stateHandler);/* target */
- QS_END_PRE_()
- }
- else {
- /* empty */
- }
- #endif /* Q_SPY */
- }
- me->state.obj = (r >= Q_RET_TRAN)
- ? me->temp.tatbl->target
- : tatbl->target;
- return r;</code>
- </operation>
- <!--${QEP::QMsm::exitToTranSource_}-->
- <operation name="exitToTranSource_" type="void" visibility="0x02" properties="0x01">
- <documentation>/*! Exit the current state up to the explicit transition source
- * @private @memberof QMsm
- *
- * @details
- * Static helper function to exit the current state configuration to the
- * transition source, which in a hierarchical state machine might be a
- * superstate of the current state.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] cs pointer to the current state
- * @param[in] ts pointer to the transition source state
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- */
- /*! @private @memberof QMsm */</documentation>
- <!--${QEP::QMsm::exitToTranSource~::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QEP::QMsm::exitToTranSource~::cs}-->
- <parameter name="cs" type="QMState const * const"/>
- <!--${QEP::QMsm::exitToTranSource~::ts}-->
- <parameter name="ts" type="QMState const * const"/>
- <!--${QEP::QMsm::exitToTranSource~::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- /* exit states from the current state to the tran. source state */
- QMState const *s = cs;
- while (s != ts) {
- /* exit action provided in state 's'? */
- if (s->exitAction != Q_ACTION_CAST(0)) {
- QS_CRIT_STAT_
- (void)(*s->exitAction)(me); /* execute the exit action */
- QS_BEGIN_PRE_(QS_QEP_STATE_EXIT, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(s->stateHandler); /* the exited state handler */
- QS_END_PRE_()
- }
- s = s->superstate; /* advance to the superstate */
- if (s == (QMState *)0) { /* reached the top of a submachine? */
- s = me->temp.obj; /* the superstate from QM_SM_EXIT() */
- Q_ASSERT_ID(510, s != (QMState *)0); /* must be valid */
- }
- }</code>
- </operation>
- <!--${QEP::QMsm::enterHistory_}-->
- <operation name="enterHistory_" type="QState" visibility="0x02" properties="0x01">
- <documentation>/*! Enter history of a composite state
- * @private @memberof QMsm
- *
- * @details
- * Static helper function to execute the segment of transition to history
- * after entering the composite state and
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] hist pointer to the history substate
- * @param[in] qs_id QS-id of this state machine (for QS local filter)
- *
- * @returns
- * #Q_RET_TRAN_INIT, if an initial transition has been executed in the last
- * entered state or #Q_RET_NULL if no such transition was taken.
- */
- /*! @private @memberof QMsm */</documentation>
- <!--${QEP::QMsm::enterHistory_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QEP::QMsm::enterHistory_::hist}-->
- <parameter name="hist" type="QMState const *const"/>
- <!--${QEP::QMsm::enterHistory_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- QMState const *s = hist;
- QMState const *ts = me->state.obj; /* transition source */
- QMState const *epath[QMSM_MAX_ENTRY_DEPTH_];
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_TRAN_HIST, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(ts->stateHandler); /* source state handler */
- QS_FUN_PRE_(hist->stateHandler); /* target state handler */
- QS_END_PRE_()
- int_fast8_t i = 0; /* transition entry path index */
- while (s != ts) {
- if (s->entryAction != Q_ACTION_CAST(0)) {
- Q_ASSERT_ID(620, i < QMSM_MAX_ENTRY_DEPTH_);
- epath[i] = s;
- ++i;
- }
- s = s->superstate;
- if (s == (QMState *)0) {
- ts = s; /* force exit from the for-loop */
- }
- }
- /* retrace the entry path in reverse (desired) order... */
- while (i > 0) {
- --i;
- (void)(*epath[i]->entryAction)(me); /* run entry action in epath[i] */
- QS_BEGIN_PRE_(QS_QEP_STATE_ENTRY, qs_id)
- QS_OBJ_PRE_(me);
- QS_FUN_PRE_(epath[i]->stateHandler); /* entered state handler */
- QS_END_PRE_()
- }
- me->state.obj = hist; /* set current state to the transition target */
- /* initial tran. present? */
- QState r;
- if (hist->initAction != Q_ACTION_CAST(0)) {
- r = (*hist->initAction)(me); /* execute the transition action */
- }
- else {
- r = Q_RET_NULL;
- }
- return r;</code>
- </operation>
- </class>
- </package>
- <!--${QF-config}-->
- <package name="QF-config" stereotype="0x02">
- <!--${QF-config::QF_MAX_ACTIVE}-->
- <attribute name="QF_MAX_ACTIVE?ndef QF_MAX_ACTIVE" type="unsigned" visibility="0x03" properties="0x00">
- <documentation>/*! Maximum number of active objects (configurable value in qf_port.h)
- * Valid values: [1U..64U]; default 32U
- */</documentation>
- <code>32U</code>
- </attribute>
- <!--${QF-config::QF_MAX_ACTIVE exceeds the maximu~}-->
- <attribute name="QF_MAX_ACTIVE exceeds the maximum of 64U? (QF_MAX_ACTIVE > 64U)" type="#error" visibility="0x04" properties="0x00"/>
- <!--${QF-config::QF_MAX_TICK_RATE}-->
- <attribute name="QF_MAX_TICK_RATE?ndef QF_MAX_TICK_RATE" type="unsigned" visibility="0x03" properties="0x00">
- <documentation>/*! Maximum number of clock rates (configurable value in qf_port.h)
- * Valid values: [0U..15U]; default 1U
- */</documentation>
- <code>1U</code>
- </attribute>
- <!--${QF-config::QF_MAX_TICK_RATE exceeds the max~}-->
- <attribute name="QF_MAX_TICK_RATE exceeds the maximum of 15U? (QF_MAX_TICK_RATE > 15U)" type="#error" visibility="0x04" properties="0x00"/>
- <!--${QF-config::QF_MAX_EPOOL}-->
- <attribute name="QF_MAX_EPOOL?ndef QF_MAX_EPOOL" type="unsigned" visibility="0x03" properties="0x00">
- <documentation>/*! Maximum number of event pools (configurable value in qf_port.h)
- * Valid values: [0U..15U]; default 3U
- *
- * @note
- * #QF_MAX_EPOOL set to zero means that dynamic events are NOT configured
- * and should not be used in the application.
- */</documentation>
- <code>3U</code>
- </attribute>
- <!--${QF-config::QF_MAX_EPOOL exceeds the maximum~}-->
- <attribute name="QF_MAX_EPOOL exceeds the maximum of 15U? (QF_MAX_EPOOL > 15U)" type="#error" visibility="0x04" properties="0x00"/>
- <!--${QF-config::QF_TIMEEVT_CTR_SIZE}-->
- <attribute name="QF_TIMEEVT_CTR_SIZE?ndef QF_TIMEEVT_CTR_SIZE" type="unsigned" visibility="0x03" properties="0x00">
- <documentation>/*! Size of the QTimeEvt counter (configurable value in qf_port.h)
- * Valid values: 1U, 2U, or 4U; default 4U
- */</documentation>
- <code>4U</code>
- </attribute>
- <!--${QF-config::QF_TIMEEVT_CTR_SIZE defined inco~}-->
- <attribute name="QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U? (QF_TIMEEVT_CTR_SIZE != 1U) && (QF_TIMEEVT_CTR_SIZE != 2U) && (QF_TIMEEVT_CTR_SIZE != 4U)" type="#error" visibility="0x04" properties="0x00"/>
- <!--${QF-config::QF_EVENT_SIZ_SIZE}-->
- <attribute name="QF_EVENT_SIZ_SIZE?ndef QF_EVENT_SIZ_SIZE" type="unsigned" visibility="0x03" properties="0x00">
- <documentation>/*! Size of the event-size (configurable value in qf_port.h)
- * Valid values: 1U, 2U, or 4U; default 2U
- */</documentation>
- <code>2U</code>
- </attribute>
- <!--${QF-config::QF_EVENT_SIZ_SIZE defined incorr~}-->
- <attribute name="QF_EVENT_SIZ_SIZE defined incorrectly, expected 1U, 2U, or 4U? (QF_EVENT_SIZ_SIZE != 1U) && (QF_EVENT_SIZ_SIZE != 2U) && (QF_EVENT_SIZ_SIZE != 4U)" type="#error" visibility="0x04" properties="0x00"/>
- </package>
- <!--${QF-types}-->
- <package name="QF-types" stereotype="0x02">
- <!--${QF-types::QPSetBits}-->
- <attribute name="QPSetBits? (8U < QF_MAX_ACTIVE) && (QF_MAX_ACTIVE <= 16U)" type="typedef uint16_t" visibility="0x04" properties="0x00">
- <documentation>/*! bitmask for the internal representation of QPSet elements */</documentation>
- </attribute>
- <!--${QF-types::QPSetBits}-->
- <attribute name="QPSetBits? (16 < QF_MAX_ACTIVE)" type="typedef uint32_t" visibility="0x04" properties="0x00"/>
- <!--${QF-types::QPSetBits}-->
- <attribute name="QPSetBits? (QF_MAX_ACTIVE <= 8U)" type="typedef uint8_t" visibility="0x04" properties="0x00"/>
- <!--${QF-types::QTimeEvtCtr}-->
- <attribute name="QTimeEvtCtr? (QF_TIMEEVT_CTR_SIZE == 2U)" type="typedef uint16_t" visibility="0x04" properties="0x00">
- <documentation>/*! Data type to store the block-size defined based on the macro
- * #QF_TIMEEVT_CTR_SIZE.
- *
- * @details
- * The dynamic range of this data type determines the maximum block
- * size that can be managed by the pool.
- */</documentation>
- </attribute>
- <!--${QF-types::QTimeEvtCtr}-->
- <attribute name="QTimeEvtCtr? (QF_TIMEEVT_CTR_SIZE == 4U)" type="typedef uint32_t" visibility="0x04" properties="0x00"/>
- <!--${QF-types::QTimeEvtCtr}-->
- <attribute name="QTimeEvtCtr? (QF_TIMEEVT_CTR_SIZE == 1U)" type="typedef uint8_t" visibility="0x04" properties="0x00"/>
- <!--${QF-types::QF_LOG2}-->
- <operation name="QF_LOG2?ndef QF_LOG2" type="uint_fast8_t" visibility="0x00" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! Log-base-2 calculation when hardware acceleration
- * is NOT provided (#QF_LOG2 not defined).
- * @static @private @memberof QF
- */
- /*! @static @private @memberof QF */</documentation>
- <!--${QF-types::QF_LOG2::x}-->
- <parameter name="x" type="QPSetBits"/>
- <code>static uint8_t const log2LUT[16] = {
- 0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U,
- 4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U
- };
- uint_fast8_t n = 0U;
- QPSetBits t;
- #if (QF_MAX_ACTIVE > 16U)
- t = (QPSetBits)(x >> 16U);
- if (t != 0U) {
- n += 16U;
- x = t;
- }
- #endif
- #if (QF_MAX_ACTIVE > 8U)
- t = (x >> 8U);
- if (t != 0U) {
- n += 8U;
- x = t;
- }
- #endif
- t = (x >> 4U);
- if (t != 0U) {
- n += 4U;
- x = t;
- }
- return n + log2LUT[x];</code>
- </operation>
- <!--${QF-types::QPrioSpec}-->
- <attribute name="QPrioSpec" type="typedef uint16_t" visibility="0x04" properties="0x00">
- <documentation>/*! Priority specification for Active Objects in QP
- *
- * @details
- * Active Object priorities in QP are integer numbers in the range
- * [1..#QF_MAX_ACTIVE], whereas the special priority number 0 is reserved
- * for the lowest-priority idle thread. The QP framework uses the *direct*
- * priority numbering, in which higher numerical values denote higher urgency.
- * For example, an AO with priority 32 has higher urgency than an AO with
- * priority 23.
- *
- * ::QPrioSpec allows an application developer to assign **two**
- * priorities to a given AO (see also Q_PRIO()):
- *
- * 1. The "QF-priority", which resides in the least-significant byte
- * of the ::QPrioSpec data type. The "QF-priority" must be **unique**
- * for each thread in the system and higher numerical values represent
- * higher urgency (direct pirority numbering).
- *
- * 2. The "preemption-threshold" priority, which resides in the most-
- * significant byte of the ::QPrioSpec data type. The second priority
- * cannot be lower than the "QF-priority", but does NOT need to be
- * unuque.
- *
- * In the QP native preemptive kernels, like QK and QXK, the "preemption-
- * threshold" priority is used as to implement the "preemption-threshold
- * scheduling" (PTS). It determines the conditions under which a given
- * thread can be *preempted* by other threads. Specifically, a given
- * thread can be preempted only by another thread with a *higher*
- * priority than the "preemption-threshold" of the original thread.
- *
- * 
- *
- * @note
- * For backwards-compatibility, ::QPrioSpec data type might contain only
- * the "QF-priority" component (and the "preemption-threshold" component
- * left at zero). In that case, the "preemption-threshold" will be assumed
- * to be the same as the "QF-priority". This corresponds exactly to the
- * previous semantics of AO priority.
- *
- * @remark
- * When QP runs on top of 3rd-party kernels/RTOSes or general-purpose
- * operating systems, sthe second priority can have different meaning,
- * depending on the specific RTOS/GPOS used.
- */</documentation>
- </attribute>
- <!--${QF-types::QSchedStatus}-->
- <attribute name="QSchedStatus" type="typedef uint_fast16_t" visibility="0x04" properties="0x00">
- <documentation>/*! The scheduler lock status used in some real-time kernels */</documentation>
- </attribute>
- <!--${QF-types::QPSet}-->
- <class name="QPSet">
- <documentation>/*! @brief Priority Set of up to #QF_MAX_ACTIVE elements
- * @class QPSet
- *
- * @details
- * The priority set represents the set of active objects that are ready to
- * run and need to be considered by the scheduling algorithm. The set is
- * capable of storing up to #QF_MAX_ACTIVE priority levels, which can be
- * configured in the rage 1..64, inclusive.
- */</documentation>
- <!--${QF-types::QPSet::bits}-->
- <attribute name="bits? (QF_MAX_ACTIVE <= 32)" type="QPSetBits volatile" visibility="0x00" properties="0x00">
- <documentation>/*! bitmask with a bit for each element */</documentation>
- </attribute>
- <!--${QF-types::QPSet::bits[2]}-->
- <attribute name="bits[2]? (32 < QF_MAX_ACTIVE)" type="QPSetBits volatile" visibility="0x00" properties="0x00">
- <documentation>/*! bitmasks with a bit for each element */</documentation>
- </attribute>
- <!--${QF-types::QPSet::setEmpty}-->
- <operation name="setEmpty" type="void" visibility="0x00" properties="0x02">
- <documentation>/*! Make the priority set empty */</documentation>
- <code>#if (QF_MAX_ACTIVE <= 32)
- me->bits = 0U;
- #else
- me->bits[0] = 0U;
- me->bits[1] = 0U;
- #endif</code>
- </operation>
- <!--${QF-types::QPSet::isEmpty}-->
- <operation name="isEmpty" type="bool" visibility="0x00" properties="0x02">
- <specifiers>const</specifiers>
- <documentation>/*! Return 'true' if the priority set is empty */</documentation>
- <code>#if (QF_MAX_ACTIVE <= 32)
- return (me->bits == 0U);
- #else
- return (me->bits[0] == 0U) ? (me->bits[1] == 0U) : false;
- #endif</code>
- </operation>
- <!--${QF-types::QPSet::notEmpty}-->
- <operation name="notEmpty" type="bool" visibility="0x00" properties="0x02">
- <specifiers>const</specifiers>
- <documentation>/*! Return 'true' if the priority set is NOT empty */</documentation>
- <code>#if (QF_MAX_ACTIVE <= 32)
- return (me->bits != 0U);
- #else
- return (me->bits[0] != 0U) ? true : (me->bits[1] != 0U);
- #endif</code>
- </operation>
- <!--${QF-types::QPSet::hasElement}-->
- <operation name="hasElement" type="bool" visibility="0x00" properties="0x02">
- <specifiers>const</specifiers>
- <documentation>/*! Return 'true' if the priority set has the element n. */</documentation>
- <!--${QF-types::QPSet::hasElement::n}-->
- <parameter name="n" type="uint_fast8_t const"/>
- <code>#if (QF_MAX_ACTIVE <= 32U)
- return (me->bits & (1U << (n - 1U))) != 0U;
- #else
- return (n <= 32U)
- ? ((me->bits[0] & ((uint32_t)1U << (n - 1U))) != 0U)
- : ((me->bits[1] & ((uint32_t)1U << (n - 33U))) != 0U);
- #endif</code>
- </operation>
- <!--${QF-types::QPSet::insert}-->
- <operation name="insert" type="void" visibility="0x00" properties="0x02">
- <documentation>/*! insert element `n` into the set (n = 1..::QF_MAX_ACTIVE) */</documentation>
- <!--${QF-types::QPSet::insert::n}-->
- <parameter name="n" type="uint_fast8_t const"/>
- <code>#if (QF_MAX_ACTIVE <= 32U)
- me->bits = (me->bits | (1U << (n - 1U)));
- #else
- if (n <= 32U) {
- me->bits[0] = (me->bits[0] | ((uint32_t)1U << (n - 1U)));
- }
- else {
- me->bits[1] = (me->bits[1] | ((uint32_t)1U << (n - 33U)));
- }
- #endif</code>
- </operation>
- <!--${QF-types::QPSet::remove}-->
- <operation name="remove" type="void" visibility="0x00" properties="0x02">
- <documentation>/*! Remove element `n` from the set (n = 1U..::QF_MAX_ACTIVE) */</documentation>
- <!--${QF-types::QPSet::remove::n}-->
- <parameter name="n" type="uint_fast8_t const"/>
- <code>#if (QF_MAX_ACTIVE <= 32U)
- me->bits = (me->bits &
- (QPSetBits)(~((QPSetBits)1U << (n - 1U))));
- #else
- if (n <= 32U) {
- (me->bits[0] = (me->bits[0] & ~((uint32_t)1U << (n - 1U))));
- }
- else {
- (me->bits[1] = (me->bits[1] & ~((uint32_t)1U << (n - 33U))));
- }
- #endif</code>
- </operation>
- <!--${QF-types::QPSet::findMax}-->
- <operation name="findMax" type="uint_fast8_t" visibility="0x00" properties="0x02">
- <specifiers>const</specifiers>
- <documentation>/*! Find the maximum element in the set, returns zero if the set is empty */</documentation>
- <code>#if (QF_MAX_ACTIVE <= 32)
- return QF_LOG2(me->bits);
- #else
- return (me->bits[1] != 0U)
- ? (QF_LOG2(me->bits[1]) + 32U)
- : (QF_LOG2(me->bits[0]));
- #endif</code>
- </operation>
- </class>
- <!--${QF-types::QSubscrList}-->
- <attribute name="QSubscrList" type="typedef QPSet" visibility="0x04" properties="0x00">
- <documentation>/*! Subscriber List (for publish-subscribe)
- *
- * @details
- * This data type represents a set of Active Objects that subscribe to
- * a given signal. The set is represented as priority-set, where each
- * bit corresponds to the unique QF-priority of an AO (see ::QPrioSpec).
- */</documentation>
- </attribute>
- </package>
- <!--${QF-macros}-->
- <package name="QF-macros" stereotype="0x02">
- <!--${QF-macros::QF_NO_MARGIN}-->
- <attribute name="QF_NO_MARGIN" type="uint_fast16_t" visibility="0x03" properties="0x00">
- <documentation>/*! Special value of margin that causes asserting failure in case
- * event allocation or event posting fails
- */</documentation>
- <code>((uint_fast16_t)0xFFFFU)</code>
- </attribute>
- <!--${QF-macros::Q_PRIO}-->
- <operation name="Q_PRIO" type="QPrioSpec" visibility="0x03" properties="0x00">
- <documentation>/*! Create a ::QPrioSpec object to specify priorty of an AO or a thread */</documentation>
- <!--${QF-macros::Q_PRIO::prio_}-->
- <parameter name="prio_" type="uint8_t"/>
- <!--${QF-macros::Q_PRIO::pthre_}-->
- <parameter name="pthre_" type="uint8_t"/>
- <code>((QPrioSpec)((prio_) | ((pthre_) << 8U)))</code>
- </operation>
- <!--${QF-macros::Q_NEW}-->
- <operation name="Q_NEW?ndef Q_EVT_CTOR" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Allocate a dynamic event (case when ::QEvt is a POD)
- *
- * @details
- * The macro calls the internal QF function QF::newX_() with
- * margin == ::QF_NO_MARGIN, which causes an assertion when the event
- * cannot be successfully allocated.
- *
- * @param[in] evtT_ event type (class name) of the event to allocate
- * @param[in] sig_ signal to assign to the newly allocated event
- *
- * @returns a valid event pointer cast to the type `evtT_`.
- *
- * @note
- * If #Q_EVT_CTOR is defined, the Q_NEW() macro becomes variadic and
- * takes all the arguments needed by the constructor of the event
- * class being allocated. The constructor is then called by means
- * of the placement-new operator.
- *
- * @usage
- * The following example illustrates dynamic allocation of an event:
- * @include qf_post.c
- */</documentation>
- <!--${QF-macros::Q_NEW::evtT_}-->
- <parameter name="evtT_" type="<event class>"/>
- <!--${QF-macros::Q_NEW::sig_}-->
- <parameter name="sig_" type="QSignal"/>
- <code>((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
- QF_NO_MARGIN, (enum_t)(sig_)))</code>
- </operation>
- <!--${QF-macros::Q_NEW}-->
- <operation name="Q_NEW?def Q_EVT_CTOR" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Asserting allocate a dynamic event
- * (case when ::QEvt is not a POD)
- */</documentation>
- <!--${QF-macros::Q_NEW::evtT_}-->
- <parameter name="evtT_" type="<event class>"/>
- <!--${QF-macros::Q_NEW::sig_}-->
- <parameter name="sig_" type="QSignal"/>
- <!--${QF-macros::Q_NEW::...}-->
- <parameter name="..." type="__VA_ARGS__"/>
- <code>\
- (evtT_##_ctor((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
- QF_NO_MARGIN, (sig_)), (enum_t)(sig_), ##__VA_ARGS__))</code>
- </operation>
- <!--${QF-macros::Q_NEW_X}-->
- <operation name="Q_NEW_X?ndef Q_EVT_CTOR" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Non-asserting allocate a dynamic event (case when ::QEvt is a POD).
- *
- * @details
- * This macro allocates a new event and sets the pointer `e_`, while
- * leaving at least `margin_` of events still available in the pool
- *
- * @param[out] e_ pointer to the newly allocated event
- * @param[in] evtT_ event type (class name) of the event to allocate
- * @param[in] margin_ number of events that must remain available
- * in the given pool after this allocation. The
- * special value ::QF_NO_MARGIN causes asserting
- * failure in case event allocation fails.
- * @param[in] sig_ signal to assign to the newly allocated event
- *
- * @returns an event pointer cast to the type `evtT_` or NULL if the
- * event cannot be allocated with the specified `margin`.
- *
- * @note
- * If #Q_EVT_CTOR is defined, the Q_NEW_X() macro becomes variadic and
- * takes all the arguments needed by the constructor of the event
- * class being allocated. The constructor is then called by means
- * of the placement-new operator.
- *
- * @usage
- * The following example illustrates dynamic allocation of an event:
- * @include qf_postx.c
- */</documentation>
- <!--${QF-macros::Q_NEW_X::e_}-->
- <parameter name="e_" type="<QEvt *>"/>
- <!--${QF-macros::Q_NEW_X::evtT_}-->
- <parameter name="evtT_" type="<event class>"/>
- <!--${QF-macros::Q_NEW_X::margin_}-->
- <parameter name="margin_" type="uint16_t"/>
- <!--${QF-macros::Q_NEW_X::sig_}-->
- <parameter name="sig_" type="QSignal"/>
- <code>((e_) = \
- (evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
- (margin_), (enum_t)(sig_)))</code>
- </operation>
- <!--${QF-macros::Q_NEW_X}-->
- <operation name="Q_NEW_X?def Q_EVT_CTOR" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Non-asserting allocate a dynamic event
- * (case when ::QEvt is not a POD)
- */</documentation>
- <!--${QF-macros::Q_NEW_X::e_}-->
- <parameter name="e_" type="<QEvt *>"/>
- <!--${QF-macros::Q_NEW_X::evtT_}-->
- <parameter name="evtT_" type="<event class>"/>
- <!--${QF-macros::Q_NEW_X::margin_}-->
- <parameter name="margin_" type="uint16_t"/>
- <!--${QF-macros::Q_NEW_X::sig_}-->
- <parameter name="sig_" type="QSignal"/>
- <!--${QF-macros::Q_NEW_X::...}-->
- <parameter name="..." type="__VA_ARGS__"/>
- <code>do { \
- (e_) = (evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
- (margin_), (enum_t)(sig_));\
- if ((e_) != (evtT_ *)0) { \
- evtT_##_ctor((e_), (enum_t)(sig_), ##__VA_ARGS__); \
- } \
- } while (false)</code>
- </operation>
- <!--${QF-macros::Q_NEW_REF}-->
- <operation name="Q_NEW_REF" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Create a new reference of the current event `e`
- *
- * @details
- * The current event processed by an active object is available only for
- * the duration of the run-to-completion (RTC) step. After that step, the
- * current event is no longer available and the framework might recycle
- * (garbage-collect) the event. The macro Q_NEW_REF() explicitly creates
- * a new reference to the current event that can be stored and used beyond
- * the current RTC step, until the reference is explicitly recycled by
- * means of the macro Q_DELETE_REF().
- *
- * @param[in,out] evtRef_ event reference to create
- * @param[in] evtT_ event type (class name) of the event reference
- *
- * @usage
- * The example **defer** in the directory `examples/win32/defer` illustrates
- * the use of Q_NEW_REF()
- *
- * @sa Q_DELETE_REF()
- */</documentation>
- <!--${QF-macros::Q_NEW_REF::evtRef_}-->
- <parameter name="evtRef_" type="<event class>"/>
- <!--${QF-macros::Q_NEW_REF::evtT_}-->
- <parameter name="evtT_" type="<event class>"/>
- <code>\
- ((evtRef_) = (evtT_ const *)QF_newRef_(e, (evtRef_)))</code>
- </operation>
- <!--${QF-macros::Q_DELETE_REF}-->
- <operation name="Q_DELETE_REF" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Delete the event reference
- *
- * @details
- * Every event reference created with the macro Q_NEW_REF() needs to be
- * eventually deleted by means of the macro Q_DELETE_REF() to avoid leaking
- * the event.
- *
- * @param[in,out] evtRef_ event reference to delete
- *
- * @usage
- * The example **defer** in the directory `examples/win32/defer` illustrates
- * the use of Q_DELETE_REF()
- *
- * @sa Q_NEW_REF()
- */</documentation>
- <!--${QF-macros::Q_DELETE_REF::evtRef_}-->
- <parameter name="evtRef_" type="<event class>"/>
- <code>do { \
- QF_deleteRef_((evtRef_)); \
- (evtRef_) = (void *)0; \
- } while (false)</code>
- </operation>
- <!--${QF-macros::QACTIVE_START}-->
- <operation name="QACTIVE_START" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Virtual call to start an active object.
- *
- * @details
- * Starts execution of the AO and registers the AO with the framework.
- *
- * @param[in,out] me_ current instance pointer (see @ref oop)
- * @param[in] prioSpec_ priority specification for the Active Object
- * @param[in] qSto_ pointer to the storage for the ring buffer of the
- * event queue (used only with the built-in ::QEQueue)
- * @param[in] qLen_ length of the event queue (in events)
- * @param[in] stkSto_ pointer to the stack storage (used only when
- * per-AO stack is needed)
- * @param[in] stkSize_ stack size (in bytes)
- * @param[in] par_ pointer to the additional port-specific parameter(s)
- * (might be NULL).
- * @usage
- * @include qf_start.c
- */</documentation>
- <!--${QF-macros::QACTIVE_START::me_}-->
- <parameter name="me_" type="<QActive subclass *>"/>
- <!--${QF-macros::QACTIVE_START::prioSpec_}-->
- <parameter name="prioSpec_" type="QPrioSpec"/>
- <!--${QF-macros::QACTIVE_START::qSto_}-->
- <parameter name="qSto_" type="QEvt const * *"/>
- <!--${QF-macros::QACTIVE_START::qLen_}-->
- <parameter name="qLen_" type="uint_fast16_t"/>
- <!--${QF-macros::QACTIVE_START::stkSto_}-->
- <parameter name="stkSto_" type="void *"/>
- <!--${QF-macros::QACTIVE_START::stkSize_}-->
- <parameter name="stkSize_" type="uint_fast16_t"/>
- <!--${QF-macros::QACTIVE_START::par_}-->
- <parameter name="par_" type="void const *"/>
- <code>do { \
- Q_ASSERT((Q_HSM_UPCAST(me_))->vptr); \
- (*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->start)( \
- (QActive *)(me_), (prioSpec_), \
- (qSto_), (qLen_), (stkSto_), (stkSize_), (par_)); \
- } while (false)</code>
- </operation>
- <!--${QF-macros::QACTIVE_POST}-->
- <operation name="QACTIVE_POST?def Q_SPY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Invoke the direct event posting facility QActive_post_()
- *
- * @details
- * This macro asserts if the queue overflows and cannot accept the event.
- *
- * @param[in,out] me_ current instance pointer (see @ref oop)
- * @param[in] e_ pointer to the event to post
- * @param[in] sender_ pointer to the sender object.
- *
- * @note
- * The `sendedr_` parameter is actually only used when QS tracing
- * is enabled (macro #Q_SPY is defined). When QS software tracing is
- * disenabled, the QACTIVE_POST() macro does not pass the `sender_`
- * parameter, so the overhead of passing this extra parameter is entirely
- * avoided.
- *
- * @note the pointer to the sender object is not necessarily a pointer
- * to an active object. In fact, if QACTIVE_POST() is called from an
- * interrupt or other context, you can create a unique object just to
- * unambiguously identify the sender of the event.
- *
- * @sa QActive_post_()
- */</documentation>
- <!--${QF-macros::QACTIVE_POST::me_}-->
- <parameter name="me_" type="<QActive subclass *>"/>
- <!--${QF-macros::QACTIVE_POST::e_}-->
- <parameter name="e_" type="QEvt const *"/>
- <!--${QF-macros::QACTIVE_POST::sender_}-->
- <parameter name="sender_" type="<sender *>"/>
- <code>\
- ((void)(*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->post)(\
- (me_), (e_), QF_NO_MARGIN, (sender_)))</code>
- </operation>
- <!--${QF-macros::QACTIVE_POST}-->
- <operation name="QACTIVE_POST?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
- <!--${QF-macros::QACTIVE_POST::me_}-->
- <parameter name="me_" type="<QActive subclass *>"/>
- <!--${QF-macros::QACTIVE_POST::e_}-->
- <parameter name="e_" type="QEvt const *"/>
- <!--${QF-macros::QACTIVE_POST::dummy}-->
- <parameter name="dummy" type=""/>
- <code>\
- ((void)(*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->post)(\
- (me_), (e_), QF_NO_MARGIN, (void *)0))</code>
- </operation>
- <!--${QF-macros::QACTIVE_POST_X}-->
- <operation name="QACTIVE_POST_X?def Q_SPY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Invoke the direct event posting facility QActive_post_()
- * without delivery guarantee
- *
- * @details
- * This macro does not assert if the queue overflows and cannot accept
- * the event with the specified margin of free slots remaining.
- *
- * @param[in,out] me_ current instance pointer (see @ref oop)
- * @param[in] e_ pointer to the event to post
- * @param[in] margin_ the minimum free slots in the queue, which
- * must still be available after posting the event.
- * The special value ::QF_NO_MARGIN causes
- * asserting failure in case event posting fails.
- * @param[in] sender_ pointer to the sender object.
- *
- * @returns
- * 'true' if the posting succeeded, and 'false' if the posting
- * failed due to insufficient margin of free entries available in
- * the queue.
- *
- * @note
- * The `sender_` parameter is actually only used when QS tracing
- * is enabled (macro #Q_SPY is defined). When QS software tracing is
- * disabled, the POST_X() macro does not pass the `sender_` parameter,
- * so the overhead of passing this extra parameter is entirely avoided.
- *
- * @note
- * The pointer to the sender object is not necessarily a pointer
- * to an active object. In fact, if POST_X() is called from an
- * interrupt or other context, you can create a unique object just to
- * unambiguously identify the sender of the event.
- *
- * @usage
- * @include qf_postx.c
- */</documentation>
- <!--${QF-macros::QACTIVE_POST_X::me_}-->
- <parameter name="me_" type="<QActive subclass *>"/>
- <!--${QF-macros::QACTIVE_POST_X::e_}-->
- <parameter name="e_" type="QEvt const *"/>
- <!--${QF-macros::QACTIVE_POST_X::margin_}-->
- <parameter name="margin_" type="uint16_t"/>
- <!--${QF-macros::QACTIVE_POST_X::sender_}-->
- <parameter name="sender_" type="<sender *>"/>
- <code>\
- ((*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->post)((me_),\
- (e_), (margin_), (sender_)))</code>
- </operation>
- <!--${QF-macros::QACTIVE_POST_X}-->
- <operation name="QACTIVE_POST_X?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
- <!--${QF-macros::QACTIVE_POST_X::me_}-->
- <parameter name="me_" type="<QActive subclass *>"/>
- <!--${QF-macros::QACTIVE_POST_X::e_}-->
- <parameter name="e_" type="QEvt const *"/>
- <!--${QF-macros::QACTIVE_POST_X::margin_}-->
- <parameter name="margin_" type="uint16_t"/>
- <!--${QF-macros::QACTIVE_POST_X::dummy}-->
- <parameter name="dummy" type=""/>
- <code>\
- ((*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->post)((me_),\
- (e_), (margin_), (void *)0))</code>
- </operation>
- <!--${QF-macros::QACTIVE_POST_LIFO}-->
- <operation name="QACTIVE_POST_LIFO" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Virtual call to post an event to an active object using the
- * Last-In-First-Out (LIFO) policy.
- *
- * @param[in,out] me_ current instance pointer (see @ref oop)
- * @param[in] e_ pointer to the event to post
- */
- </documentation>
- <!--${QF-macros::QACTIVE_POST_LIF~::me_}-->
- <parameter name="me_" type="<QActive subclass *>"/>
- <!--${QF-macros::QACTIVE_POST_LIF~::e_}-->
- <parameter name="e_" type="QEvt const *"/>
- <code>\
- ((*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->postLIFO)( \
- (me_), (e_)))</code>
- </operation>
- <!--${QF-macros::QACTIVE_PUBLISH}-->
- <operation name="QACTIVE_PUBLISH?def Q_SPY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Publish an event to all subscriber Active Objects.
- *
- * @details
- * If #Q_SPY is defined, this macro calls QActive_publish_() with
- * the `sender_` parameter to identify the publisher of the event.
- * Otherwise, `sender_` is not used.
- *
- * @param[in] e_ pointer to the posted event
- * @param[in] sender_ pointer to the sender object (actually used
- * only when #Q_SPY is defined)
- *
- * @note
- * The pointer to the `sender_` object is not necessarily a pointer
- * to an active object. In fact, if QACTIVE_PUBLISH() is called from an
- * interrupt or other context, you can create a unique object just to
- * unambiguously identify the sender of the event.
- *
- * @sa QActive_publish_()
- */</documentation>
- <!--${QF-macros::QACTIVE_PUBLISH::e_}-->
- <parameter name="e_" type="QEvt const *"/>
- <!--${QF-macros::QACTIVE_PUBLISH::sender_}-->
- <parameter name="sender_" type="<void const *>"/>
- <code>\
- (QActive_publish_((e_), (void const *)(sender_), (sender_)->prio))</code>
- </operation>
- <!--${QF-macros::QACTIVE_PUBLISH}-->
- <operation name="QACTIVE_PUBLISH?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
- <!--${QF-macros::QACTIVE_PUBLISH::e_}-->
- <parameter name="e_" type="QEvt const *"/>
- <!--${QF-macros::QACTIVE_PUBLISH::dummy}-->
- <parameter name="dummy" type=""/>
- <code>(QActive_publish_((e_), (void *)0, 0U))</code>
- </operation>
- <!--${QF-macros::QTIMEEVT_TICK_X}-->
- <operation name="QTIMEEVT_TICK_X?def Q_SPY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Invoke the system clock tick processing QTimeEvt_tick_()
- *
- * @details
- * This macro is the recommended way of invoking clock tick processing,
- * because it provides the vital information for software tracing and
- * avoids any overhead when the tracing is disabled.
- *
- * @param[in] tickRate_ clock tick rate to be serviced through this call
- * @param[in] sender_ pointer to the sender object. This parameter
- * is actually only used when QS software tracing is enabled
- * (macro #Q_SPY is defined)
- * @note
- * When QS software tracing is disabled, the macro calls QTimeEvt_tick_()
- * without the `sender` parameter, so the overhead of passing this
- * extra parameter is entirely avoided.
- *
- * @note
- * The pointer to the sender object is not necessarily a pointer
- * to an active object. In fact, when QTIMEEVT_TICK_X() is called from
- * an interrupt, you would create a unique object just to unambiguously
- * identify the ISR as the sender of the time events.
- *
- * @sa QTimeEvt_tick_()
- */</documentation>
- <!--${QF-macros::QTIMEEVT_TICK_X::tickRate_}-->
- <parameter name="tickRate_" type="uint8_t"/>
- <!--${QF-macros::QTIMEEVT_TICK_X::sender_}-->
- <parameter name="sender_" type="<sender *>"/>
- <code>\
- (QTimeEvt_tick_((tickRate_), (sender_)))</code>
- </operation>
- <!--${QF-macros::QTIMEEVT_TICK_X}-->
- <operation name="QTIMEEVT_TICK_X?ndef Q_SPY" type="void" visibility="0x03" properties="0x00">
- <!--${QF-macros::QTIMEEVT_TICK_X::tickRate_}-->
- <parameter name="tickRate_" type="uint8_t"/>
- <!--${QF-macros::QTIMEEVT_TICK_X::dummy}-->
- <parameter name="dummy" type=""/>
- <code>\
- (QTimeEvt_tick_((tickRate_), (void *)0))</code>
- </operation>
- <!--${QF-macros::QTIMEEVT_TICK}-->
- <operation name="QTIMEEVT_TICK" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Invoke the system clock tick processing
- * for tick rate 0
- */</documentation>
- <!--${QF-macros::QTIMEEVT_TICK::sender_}-->
- <parameter name="sender_" type="<sender *>"/>
- <code>QTIMEEVT_TICK_X(0U, (sender_))</code>
- </operation>
- <!--${QF-macros::QF_CRIT_EXIT_NOP}-->
- <operation name="QF_CRIT_EXIT_NOP?ndef QF_CRIT_EXIT_NOP" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! No-operation for exiting a critical section
- *
- * @details
- * In some QF ports the critical section exit takes effect only on the
- * next machine instruction. If this next instruction is another entry
- * to a critical section, the critical section won't be really exited,
- * but rather the two adjecent critical sections would be merged.
- * The QF_CRIT_EXIT_NOP() macro contains minimal code required to
- * prevent such merging of critical sections in such merging of
- * critical sections in QF ports, in which it can occur.
- */</documentation>
- <code>((void)0)</code>
- </operation>
- <!--${QF-macros::QF_TICK_X}-->
- <operation name="QF_TICK_X" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Invoke the system clock tick processing
- *
- * @deprecated
- * superseded by QTIMEEVT_TICK_X()
- */</documentation>
- <!--${QF-macros::QF_TICK_X::tickRate_}-->
- <parameter name="tickRate_" type="uint8_t"/>
- <!--${QF-macros::QF_TICK_X::sender_}-->
- <parameter name="sender_" type="<sender *>"/>
- <code>QTIMEEVT_TICK_X((tickRate_), (sender_))</code>
- </operation>
- <!--${QF-macros::QF_TICK}-->
- <operation name="QF_TICK" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Invoke the system clock tick processing for tick rate 0
- *
- * @deprecated
- * superseded by QTIMEEVT_TICK()
- */</documentation>
- <!--${QF-macros::QF_TICK::sender_}-->
- <parameter name="sender_" type="<sender *>"/>
- <code>QTIMEEVT_TICK(sender_)</code>
- </operation>
- <!--${QF-macros::QF_PUBLISH}-->
- <operation name="QF_PUBLISH" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Publish an event to all subscriber Active Objects.
- *
- * @deprecated
- * superseded by QACTIVE_PUBLISH()
- */</documentation>
- <!--${QF-macros::QF_PUBLISH::e_}-->
- <parameter name="e_" type="QEvt const *"/>
- <!--${QF-macros::QF_PUBLISH::sender_}-->
- <parameter name="sender_" type="<void const *>"/>
- <code>QACTIVE_PUBLISH((e_), (sender_))</code>
- </operation>
- </package>
- <!--${QF}-->
- <package name="QF" stereotype="0x05">
- <!--${QF::QActive}-->
- <class name="QActive" superclass="QEP::QHsm">
- <documentation>/*! @brief Active object class (based on the QHsm implementation strategy)
- * @class QActive
- * @extends QHsm
- *
- * @details
- * Active objects are encapsulated tasks (each containing an event queue and
- * a state machine) that communicate with one another asynchronously by
- * sending and receiving events. Within an active object, events are
- * processed in a run-to-completion (RTC) fashion, while QF encapsulates
- * all the details of thread-safe event exchange and queuing.<br>
- *
- * QActive represents an active object that uses the QHsm-style
- * implementation strategy for state machines. This strategy is tailored
- * to manual coding, but it is also supported by the QM modeling tool.
- * The resulting code is slower than in the ::QMsm-style implementation
- * strategy.
- *
- * @note
- * QActive is not intended to be instantiated directly, but rather serves
- * as the abstract base class for derivation of active objects in the
- * applications.
- *
- * @sa QMActive
- *
- * @usage
- * The following example illustrates how to derive an active object from
- * QActive.
- * @include qf_qactive.c
- */</documentation>
- <!--${QF::QActive::eQueue}-->
- <attribute name="eQueue?def QF_EQUEUE_TYPE" type="QF_EQUEUE_TYPE" visibility="0x02" properties="0x00">
- <documentation>/*! OS-dependent event-queue type
- * @private @memberof QActive
- *
- * @details
- * The type of the queue depends on the underlying operating system or
- * a kernel. Many kernels support "message queues" that can be adapted
- * to deliver QF events to the active object. Alternatively, QF provides
- * a native event queue implementation that can be used as well.
- *
- * @note
- * The native QF event queue is configured by defining the macro
- * #QF_EQUEUE_TYPE as ::QEQueue.
- */</documentation>
- </attribute>
- <!--${QF::QActive::osObject}-->
- <attribute name="osObject?def QF_OS_OBJECT_TYPE" type="QF_OS_OBJECT_TYPE" visibility="0x02" properties="0x00">
- <documentation>/*! OS-dependent per-thread object
- * @private @memberof QActive
- *
- * @details
- * This data might be used in various ways, depending on the QF port.
- * In some ports me->osObject is used to block the calling thread when
- * the native QF queue is empty. In other QF ports the OS-dependent
- * object might be used differently.
- */</documentation>
- </attribute>
- <!--${QF::QActive::thread}-->
- <attribute name="thread?def QF_THREAD_TYPE" type="QF_THREAD_TYPE" visibility="0x02" properties="0x00">
- <documentation>/*! OS-dependent representation of the thread of the active object
- * @private @memberof QActive
- *
- * @details
- * This data might be used in various ways, depending on the QF port.
- * In some ports me->thread is used store the thread handle. In other ports
- * me->thread can be a pointer to the Thread-Local-Storage (TLS).
- */</documentation>
- </attribute>
- <!--${QF::QActive::prio}-->
- <attribute name="prio" type="uint8_t" visibility="0x00" properties="0x00">
- <documentation>/*! QF-priority [1..#QF_MAX_ACTIVE] of this AO.
- * @private @memberof QActive
- * @sa ::QPrioSpec
- */</documentation>
- </attribute>
- <!--${QF::QActive::pthre}-->
- <attribute name="pthre" type="uint8_t" visibility="0x00" properties="0x00">
- <documentation>/*! preemption-threshold [1..#QF_MAX_ACTIVE] of this AO.
- * @private @memberof QActive
- * @sa ::QPrioSpec
- */</documentation>
- </attribute>
- <!--${QF::QActive::active_[QF_MAX_ACTIVE + 1U]}-->
- <attribute name="active_[QF_MAX_ACTIVE + 1U]" type="QActive *" visibility="0x00" properties="0x01">
- <documentation>/*! Internal array of registered active objects
- * @static @private @memberof QActive
- */</documentation>
- </attribute>
- <!--${QF::QActive::subscrList_}-->
- <attribute name="subscrList_" type="QSubscrList *" visibility="0x00" properties="0x01">
- <documentation>/*! pointer to the array of all subscriber AOs for a given event signal.
- * @static @private @memberof QActive
- */</documentation>
- </attribute>
- <!--${QF::QActive::maxPubSignal_}-->
- <attribute name="maxPubSignal_" type="enum_t" visibility="0x00" properties="0x01">
- <documentation>/*! The maximum published signal (the size of the subscrList_ array)
- * @static @private @memberof QActive
- */</documentation>
- </attribute>
- <!--${QF::QActive::registry_[QF_MAX_ACTIVE + 1U]}-->
- <attribute name="registry_[QF_MAX_ACTIVE + 1U]" type="QActive *" visibility="0x02" properties="0x01">
- <documentation>/*! Internal array of registered active objects
- * @static @private @memberof QActive
- */</documentation>
- </attribute>
- <!--${QF::QActive::ctor}-->
- <operation name="ctor" type="void" visibility="0x01" properties="0x00">
- <documentation>/*! ::QActive constructor (abstract base class)
- * @protected @memberof QActive
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] initial pointer to the top-most initial state-handler
- * function in the derived active object
- * @sa QHsm_ctor()
- */
- /*! @protected @memberof QActive */</documentation>
- <!--${QF::QActive::ctor::initial}-->
- <parameter name="initial" type="QStateHandler const"/>
- <code>static QActiveVtable const vtable = { /* QActive virtual table */
- { &QHsm_init_,
- &QHsm_dispatch_
- #ifdef Q_SPY
- ,&QHsm_getStateHandler_
- #endif
- },
- &QActive_start_,
- &QActive_post_,
- &QActive_postLIFO_
- };
- /* clear the whole QActive object, so that the framework can start
- * correctly even if the startup code fails to clear the uninitialized
- * data (as is required by the C Standard).
- */
- QF_bzero(me, sizeof(*me));
- QHsm_ctor(&me->super, initial); /* explicitly call superclass' ctor */
- me->super.vptr = &vtable.super; /* hook the vptr to QActive vtable */</code>
- </operation>
- <!--${QF::QActive::start_}-->
- <operation name="start_" type="void" visibility="0x02" properties="0x00">
- <documentation>/*! Starts execution of an active object and registers the object
- * with the framework
- * @private @memberof QActive
- *
- * @details
- * Starts execution of the AO and registers the AO with the framework.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] prioSpec priority specification for the AO (See ::QPrioSpec)
- * @param[in] qSto pointer to the storage for the ring buffer of the
- * event queue
- * @param[in] qLen length of the event queue [# ::QEvt* pointers]
- * @param[in] stkSto pointer to the stack storage (might be NULL)
- * @param[in] stkSize stack size [bytes]
- * @param[in] par pointer to an extra parameter (might be NULL)
- *
- * @usage
- * The following example shows starting an AO when a per-task stack
- * is needed:
- * @include qf_start.c
- */
- /*! @private @memberof QActive */</documentation>
- <!--${QF::QActive::start_::prioSpec}-->
- <parameter name="prioSpec" type="QPrioSpec const"/>
- <!--${QF::QActive::start_::qSto}-->
- <parameter name="qSto" type="QEvt const * * const"/>
- <!--${QF::QActive::start_::qLen}-->
- <parameter name="qLen" type="uint_fast16_t const"/>
- <!--${QF::QActive::start_::stkSto}-->
- <parameter name="stkSto" type="void * const"/>
- <!--${QF::QActive::start_::stkSize}-->
- <parameter name="stkSize" type="uint_fast16_t const"/>
- <!--${QF::QActive::start_::par}-->
- <parameter name="par" type="void const * const"/>
- </operation>
- <!--${QF::QActive::stop}-->
- <operation name="stop?def QF_ACTIVE_STOP" type="void" visibility="0x01" properties="0x00">
- <documentation>/*! Stops execution of an active object and removes it from the
- * framework's supervision
- * @protected @memberof QActive
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @attention
- * QActive_stop() must be called only from the AO that is about
- * to stop its execution. By that time, any pointers or references
- * to the AO are considered invalid (dangling) and it becomes
- * illegal for the rest of the application to post events to the AO.
- */
- /*! @protected @memberof QActive */</documentation>
- </operation>
- <!--${QF::QActive::post_}-->
- <operation name="post_" type="bool" visibility="0x02" properties="0x00">
- <documentation>/*! Posts an event `e` directly to the event queue of the active object
- * using the First-In-First-Out (FIFO) policy.
- * @private @memberof QActive
- *
- * @details
- * Direct event posting is the simplest asynchronous communication
- * method available in QF.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] e pointer to the event to be posted
- * @param[in] margin number of required free slots in the queue
- * after posting the event or ::QF_NO_MARGIN.
- * @param[in] sender pointer to a sender object (used in QS only)
- *
- * @returns
- * 'true' (success) if the posting succeeded (with the provided margin)
- * and 'false' (failure) when the posting fails.
- *
- * @precondition{qf_actq,100}
- * - event pointer must be valid
- *
- * @postcondition{qf_actq,190}
- * - the event must be posted if (`margin` == ::QF_NO_MARGIN)
- *
- * @attention
- * For `margin` == ::QF_NO_MARGIN, this function will assert internally
- * if the event posting fails. In that case, it is unnecessary to check
- * the retrun value from this function.
- *
- * @note
- * This function might be implemented differently in various QP/C++
- * ports. The provided implementation assumes that the ::QEQueue
- * class is used for the ::QActive event queue.
- *
- * @sa
- * QActive_postLIFO()
- *
- * @usage
- * @include qf_post.c
- */
- /*! @private @memberof QActive */</documentation>
- <!--${QF::QActive::post_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QF::QActive::post_::margin}-->
- <parameter name="margin" type="uint_fast16_t const"/>
- <!--${QF::QActive::post_::sender}-->
- <parameter name="sender" type="void const * const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(sender);
- #endif
- Q_REQUIRE_ID(100, e != (QEvt *)0);
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QEQueueCtr nFree = me->eQueue.nFree; /* get volatile into temporary */
- /* test-probe#1 for faking queue overflow */
- QS_TEST_PROBE_DEF(&QActive_post_)
- QS_TEST_PROBE_ID(1,
- nFree = 0U;
- )
- bool status;
- if (margin == QF_NO_MARGIN) {
- if (nFree > 0U) {
- status = true; /* can post */
- }
- else {
- status = false; /* cannot post */
- Q_ERROR_CRIT_(190); /* must be able to post the event */
- }
- }
- else if (nFree > (QEQueueCtr)margin) {
- status = true; /* can post */
- }
- else {
- status = false; /* cannot post, but don't assert */
- }
- /* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- QEvt_refCtr_inc_(e); /* increment the reference counter */
- }
- if (status) { /* can post the event? */
- --nFree; /* one free entry just used up */
- me->eQueue.nFree = nFree; /* update the original */
- if (me->eQueue.nMin > nFree) {
- me->eQueue.nMin = nFree; /* increase minimum so far */
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(sender); /* the sender object */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this active object (recipient) */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* number of free entries */
- QS_EQC_PRE_(me->eQueue.nMin); /* min number of free entries */
- QS_END_NOCRIT_PRE_()
- #ifdef Q_UTEST
- /* callback to examine the posted event under the same conditions
- * as producing the #QS_QF_ACTIVE_POST trace record, which are:
- * the local filter for this AO ('me->prio') is set
- */
- if (QS_LOC_CHECK_(me->prio)) {
- /* callback to examine the posted event */
- QS_onTestPost(sender, me, e, status);
- }
- #endif
- /* empty queue? */
- if (me->eQueue.frontEvt == (QEvt *)0) {
- me->eQueue.frontEvt = e; /* deliver event directly */
- QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
- }
- /* queue is not empty, insert event into the ring-buffer */
- else {
- /* insert event into the ring buffer (FIFO) */
- me->eQueue.ring[me->eQueue.head] = e;
- if (me->eQueue.head == 0U) { /* need to wrap head? */
- me->eQueue.head = me->eQueue.end; /* wrap around */
- }
- --me->eQueue.head; /* advance the head (counter clockwise) */
- }
- QF_CRIT_X_();
- }
- else { /* cannot post the event */
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_ATTEMPT, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(sender); /* the sender object */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this active object (recipient) */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* number of free entries */
- QS_EQC_PRE_(margin); /* margin requested */
- QS_END_NOCRIT_PRE_()
- #ifdef Q_UTEST
- /* callback to examine the posted event under the same conditions
- * as producing the #QS_QF_ACTIVE_POST trace record, which are:
- * the local filter for this AO ('me->prio') is set
- */
- if (QS_LOC_CHECK_(me->prio)) {
- QS_onTestPost(sender, me, e, status);
- }
- #endif
- QF_CRIT_X_();
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e); /* recycle the event to avoid a leak */
- #endif
- }
- return status;</code>
- </operation>
- <!--${QF::QActive::postLIFO_}-->
- <operation name="postLIFO_" type="void" visibility="0x02" properties="0x00">
- <documentation>/*! Posts an event `e` directly to the event queue of the active object
- * using the Last-In-First-Out (LIFO) policy.
- * @private @memberof QActive
- *
- * @details
- * The LIFO policy should be used only for self-posting and with caution,
- * because it alters order of events in the queue.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] e pointer to the event to be posted
- *
- * @precondition{qf_actq,200}
- * - the queue must be able to accept the event (cannot overflow)
- *
- * @note
- * This function might be implemented differently in various QP/C++
- * ports. The provided implementation assumes that the ::QEQueue
- * class is used for the QActive event queue.
- *
- * @sa
- * QActive_post()
- */
- /*! @private @memberof QActive */</documentation>
- <!--${QF::QActive::postLIFO_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QEQueueCtr nFree = me->eQueue.nFree; /* get volatile into temporary */
- /* test-probe#1 for faking queue overflow */
- QS_TEST_PROBE_DEF(&QActive_postLIFO_)
- QS_TEST_PROBE_ID(1,
- nFree = 0U;
- )
- Q_REQUIRE_CRIT_(200, nFree != 0U);
- /* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- QEvt_refCtr_inc_(e); /* increment the reference counter */
- }
- --nFree; /* one free entry just used up */
- me->eQueue.nFree = nFree; /* update the original */
- if (me->eQueue.nMin > nFree) {
- me->eQueue.nMin = nFree; /* update minimum so far */
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_LIFO, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this active object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_);/* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* # free entries */
- QS_EQC_PRE_(me->eQueue.nMin); /* min number of free entries */
- QS_END_NOCRIT_PRE_()
- #ifdef Q_UTEST
- /* callback to examine the posted event under the same conditions
- * as producing the #QS_QF_ACTIVE_POST trace record, which are:
- * the local filter for this AO ('me->prio') is set
- */
- if (QS_LOC_CHECK_(me->prio)) {
- QS_onTestPost((QActive *)0, me, e, true);
- }
- #endif
- QEvt const * const frontEvt = me->eQueue.frontEvt;
- me->eQueue.frontEvt = e; /* deliver the event directly to the front */
- /* was the queue empty? */
- if (frontEvt == (QEvt *)0) {
- QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
- }
- /* queue was not empty, leave the event in the ring-buffer */
- else {
- ++me->eQueue.tail;
- /* need to wrap the tail? */
- if (me->eQueue.tail == me->eQueue.end) {
- me->eQueue.tail = 0U; /* wrap around */
- }
- me->eQueue.ring[me->eQueue.tail] = frontEvt;
- }
- QF_CRIT_X_();</code>
- </operation>
- <!--${QF::QActive::get_}-->
- <operation name="get_" type="QEvt const *" visibility="0x02" properties="0x00">
- <documentation>/*! Get an event from the event queue of an active object
- * @private @memberof QActive
- *
- * @details
- * The behavior of this function depends on the kernel used in the
- * QF port. For built-in kernels (Vanilla or QK) the function can be
- * called only when the queue is not empty, so it doesn't block. For
- * a blocking kernel/OS the function can block and wait for delivery
- * of an event.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @returns
- * A pointer to the received event. The returned pointer is guaranteed
- * to be valid (can't be NULL).
- *
- * @note
- * This function might be implemented differently in various QP/C++
- * ports. The provided implementation assumes that the ::QEQueue
- * class is used for the QActive event queue.
- */
- /*! @private @memberof QActive */</documentation>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QACTIVE_EQUEUE_WAIT_(me); /* wait for event to arrive directly */
- /* always remove event from the front */
- QEvt const * const e = me->eQueue.frontEvt;
- QEQueueCtr const nFree = me->eQueue.nFree + 1U; /* get volatile into tmp */
- me->eQueue.nFree = nFree; /* update the number of free */
- /* any events in the ring buffer? */
- if (nFree <= me->eQueue.end) {
- /* remove event from the tail */
- me->eQueue.frontEvt = me->eQueue.ring[me->eQueue.tail];
- if (me->eQueue.tail == 0U) { /* need to wrap the tail? */
- me->eQueue.tail = me->eQueue.end; /* wrap around */
- }
- --me->eQueue.tail;
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this active object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* # free entries */
- QS_END_NOCRIT_PRE_()
- }
- else {
- me->eQueue.frontEvt = (QEvt *)0; /* queue becomes empty */
- /* all entries in the queue must be free (+1 for fronEvt) */
- Q_ASSERT_CRIT_(310, nFree == (me->eQueue.end + 1U));
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET_LAST, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this active object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_END_NOCRIT_PRE_()
- }
- QF_CRIT_X_();
- return e;</code>
- </operation>
- <!--${QF::QActive::subscribe}-->
- <operation name="subscribe" type="void" visibility="0x00" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! Subscribes for delivery of signal `sig` to the active object
- * @public @memberof QActive
- *
- * @details
- * This function is part of the Publish-Subscribe event delivery
- * mechanism available in QF. Subscribing to an event means that the
- * framework will start posting all published events with a given signal
- * `sig` to the event queue of the active object.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] sig event signal to subscribe
- *
- * @precondition{qf_ps,300}
- * - signal must be in range of subscribe scignals
- * - subscriber AO priority must be in range
- * - the AO must be registered (started)
- *
- * The following example shows how the Table active object subscribes
- * to three signals in the initial transition:
- * @include qf_subscribe.cpp
- *
- * @sa
- * QActive_publish_(), QActive_unsubscribe(), and
- * QActive_unsubscribeAll()
- */
- /*! @public @memberof QActive */</documentation>
- <!--${QF::QActive::subscribe::sig}-->
- <parameter name="sig" type="enum_t const"/>
- <code>uint_fast8_t const p = (uint_fast8_t)me->prio;
- Q_REQUIRE_ID(300, ((enum_t)Q_USER_SIG <= sig)
- && (sig < QActive_maxPubSignal_)
- && (0U < p) && (p <= QF_MAX_ACTIVE)
- && (QActive_registry_[p] == me));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_SUBSCRIBE, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this active object */
- QS_END_NOCRIT_PRE_()
- /* set the priority bit */
- QPSet_insert(&QActive_subscrList_[sig], p);
- QF_CRIT_X_();</code>
- </operation>
- <!--${QF::QActive::unsubscribe}-->
- <operation name="unsubscribe" type="void" visibility="0x00" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! Unsubscribes from the delivery of signal `sig` to the active object
- * @public @memberof QActive
- *
- * @details
- * This function is part of the Publish-Subscribe event delivery
- * mechanism available in QF. Un-subscribing from an event means that
- * the framework will stop posting published events with a given signal
- * `sig` to the event queue of the active object.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] sig event signal to unsubscribe
- *
- * @precondition{qf_ps,400}
- * - signal must be in range of subscribe scignals
- * - subscriber AO priority must be in range
- * - the AO must be registered (started)
- *
- * @note
- * Due to the latency of event queues, an active object should NOT
- * assume that a given signal `sig` will never be dispatched to the
- * state machine of the active object after un-subscribing from that
- * signal. The event might be already in the queue, or just about to
- * be posted and the un-subscribe operation will not flush such events.
- *
- * @note
- * Un-subscribing from a signal that has never been subscribed in the
- * first place is considered an error and QF will raise an assertion.
- *
- * @sa
- * QActive_publish_(), QActive_subscribe(), and
- * QActive_unsubscribeAll()
- */
- /*! @public @memberof QActive */</documentation>
- <!--${QF::QActive::unsubscribe::sig}-->
- <parameter name="sig" type="enum_t const"/>
- <code>uint_fast8_t const p = (uint_fast8_t)me->prio;
- Q_REQUIRE_ID(400, ((enum_t)Q_USER_SIG <= sig)
- && (sig < QActive_maxPubSignal_)
- && (0U < p) && (p <= QF_MAX_ACTIVE)
- && (QActive_registry_[p] == me));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_UNSUBSCRIBE, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this active object */
- QS_END_NOCRIT_PRE_()
- /* clear priority bit */
- QPSet_remove(&QActive_subscrList_[sig], p);
- QF_CRIT_X_();</code>
- </operation>
- <!--${QF::QActive::unsubscribeAll}-->
- <operation name="unsubscribeAll" type="void" visibility="0x00" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! Unsubscribes from the delivery of all signals to the active object
- * @public @memberof QActive
- *
- * @details
- * This function is part of the Publish-Subscribe event delivery
- * mechanism available in QF. Un-subscribing from all events means that
- * the framework will stop posting any published events to the event
- * queue of the active object.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @precondition{qf_ps,500}
- * - subscriber AO priority must be in range
- * - the AO must be registered (started)
- *
- * @note
- * Due to the latency of event queues, an active object should NOT
- * assume that no events will ever be dispatched to the state machine of
- * the active object after un-subscribing from all events.
- * The events might be already in the queue, or just about to be posted
- * and the un-subscribe operation will not flush such events. Also, the
- * alternative event-delivery mechanisms, such as direct event posting or
- * time events, can be still delivered to the event queue of the active
- * object.
- *
- * @sa
- * QActive_publish_(), QActive_subscribe(), and QActive_unsubscribe()
- */
- /*! @public @memberof QActive */</documentation>
- <code>uint_fast8_t const p = (uint_fast8_t)me->prio;
- Q_REQUIRE_ID(500, (0U < p) && (p <= QF_MAX_ACTIVE)
- && (QActive_registry_[p] == me));
- for (enum_t sig = (enum_t)Q_USER_SIG; sig < QActive_maxPubSignal_; ++sig) {
- QF_CRIT_STAT_
- QF_CRIT_E_();
- if (QPSet_hasElement(&QActive_subscrList_[sig], p)) {
- QPSet_remove(&QActive_subscrList_[sig], p);
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_UNSUBSCRIBE, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this active object */
- QS_END_NOCRIT_PRE_()
- }
- QF_CRIT_X_();
- /* prevent merging critical sections */
- QF_CRIT_EXIT_NOP();
- }</code>
- </operation>
- <!--${QF::QActive::psInit}-->
- <operation name="psInit" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Publish event to all subscribers of a given signal `e->sig`
- * @static @public @memberof QActive
- *
- * @details
- * This function posts (using the FIFO policy) the event @a e to **all**
- * active objects that have subscribed to the signal @a e->sig, which is
- * called _multicasting_. The multicasting performed in this function is
- * very efficient based on reference-counting inside the published event
- * ("zero-copy" event multicasting). This function is designed to be
- * callable from any part of the system, including ISRs, device drivers,
- * and active objects.
- *
- * @note
- * To avoid any unexpected re-ordering of events posted into AO queues,
- * the event multicasting is performed with scheduler **locked**.
- * However, the scheduler is locked only up to the priority level of
- * the highest-priority subscriber, so any AOs of even higher priority,
- * which did not subscribe to this event are *not* affected.
- */
- /*! @static @public @memberof QActive */</documentation>
- <!--${QF::QActive::psInit::subscrSto}-->
- <parameter name="subscrSto" type="QSubscrList * const"/>
- <!--${QF::QActive::psInit::maxSignal}-->
- <parameter name="maxSignal" type="enum_t const"/>
- <code>QActive_subscrList_ = subscrSto;
- QActive_maxPubSignal_ = maxSignal;
- /* zero the subscriber list, so that the framework can start correctly
- * even if the startup code fails to clear the uninitialized data
- * (as is required by the C Standard).
- */
- QF_bzero(subscrSto, (uint_fast16_t)maxSignal * sizeof(QSubscrList));</code>
- </operation>
- <!--${QF::QActive::publish_}-->
- <operation name="publish_" type="void" visibility="0x02" properties="0x01">
- <documentation>/*! Publish event to all subscribers of a given signal `e->sig`
- * @static @private @memberof QActive
- *
- * @details
- * This function posts (using the FIFO policy) the event @a e to **all**
- * active objects that have subscribed to the signal @a e->sig, which is
- * called _multicasting_. The multicasting performed in this function is
- * very efficient based on reference-counting inside the published event
- * ("zero-copy" event multicasting). This function is designed to be
- * callable from any part of the system, including ISRs, device drivers,
- * and active objects.
- *
- * @precondition{qf_ps,200}
- * - the published signal must be within the configured range
- *
- * @note
- * To avoid any unexpected re-ordering of events posted into AO queues,
- * the event multicasting is performed with scheduler **locked**.
- * However, the scheduler is locked only up to the priority level of
- * the highest-priority subscriber, so any AOs of even higher priority,
- * which did not subscribe to this event are *not* affected.
- */
- /*! @static @private @memberof QActive */</documentation>
- <!--${QF::QActive::publish_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QF::QActive::publish_::sender}-->
- <parameter name="sender" type="void const * const"/>
- <!--${QF::QActive::publish_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(sender);
- Q_UNUSED_PAR(qs_id);
- #endif
- Q_REQUIRE_ID(200, e->sig < (QSignal)QActive_maxPubSignal_);
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QS_BEGIN_NOCRIT_PRE_(QS_QF_PUBLISH, qs_id)
- QS_TIME_PRE_(); /* the timestamp */
- QS_OBJ_PRE_(sender); /* the sender object */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_2U8_PRE_(e->poolId_, e->refCtr_);/* pool Id & ref Count */
- QS_END_NOCRIT_PRE_()
- /* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- /* NOTE: The reference counter of a dynamic event is incremented to
- * prevent premature recycling of the event while the multicasting
- * is still in progress. At the end of the function, the garbage
- * collector step (QF_gc()) decrements the reference counter and
- * recycles the event if the counter drops to zero. This covers the
- * case when the event was published without any subscribers.
- */
- QEvt_refCtr_inc_(e);
- }
- /* make a local, modifiable copy of the subscriber list */
- QPSet subscrList = QActive_subscrList_[e->sig];
- QF_CRIT_X_();
- if (QPSet_notEmpty(&subscrList)) { /* any subscribers? */
- /* the highest-prio subscriber */
- uint_fast8_t p = QPSet_findMax(&subscrList);
- QActive *a = QActive_registry_[p];
- QF_SCHED_STAT_
- QF_SCHED_LOCK_(a->prio); /* lock the scheduler up to AO's prio */
- do { /* loop over all subscribers */
- /* the prio of the AO must be registered with the framework */
- Q_ASSERT_ID(210, a != (QActive *)0);
- /* QACTIVE_POST() asserts internally if the queue overflows */
- QACTIVE_POST(a, e, sender);
- QPSet_remove(&subscrList, p); /* remove the handled subscriber */
- if (QPSet_notEmpty(&subscrList)) { /* still more subscribers? */
- /* highest-prio subscriber */
- p = QPSet_findMax(&subscrList);
- a = QActive_registry_[p];
- }
- else {
- p = 0U; /* no more subscribers */
- }
- } while (p != 0U);
- QF_SCHED_UNLOCK_(); /* unlock the scheduler */
- }
- /* The following garbage collection step decrements the reference counter
- * and recycles the event if the counter drops to zero. This covers both
- * cases when the event was published with or without any subscribers.
- */
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e); /* recycle the event to avoid a leak */
- #endif</code>
- </operation>
- <!--${QF::QActive::defer}-->
- <operation name="defer" type="bool" visibility="0x01" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! Defer an event to a given separate event queue
- * @protected @memberof QActive
- *
- * @details
- * This function is part of the event deferral support. An active object
- * uses this function to defer an event `e` to the QF-supported native
- * event queue `eq`. QF correctly accounts for another outstanding
- * reference to the event and will not recycle the event at the end of
- * the RTC step. Later, the active object might recall one event at a
- * time from the event queue.
- *
- * @param[in] eq pointer to a "raw" thread-safe queue to recall
- * an event from.
- * @param[in] e pointer to the event to be deferred
- *
- * @returns
- * 'true' (success) when the event could be deferred and 'false'
- * (failure) if event deferral failed due to overflowing the queue.
- *
- * An active object can use multiple event queues to defer events of
- * different kinds.
- *
- * @sa
- * QActive_recall(), ::QEQueue, QActive_flushDeferred()
- */
- /*! @protected @memberof QActive */</documentation>
- <!--${QF::QActive::defer::eq}-->
- <parameter name="eq" type="QEQueue * const"/>
- <!--${QF::QActive::defer::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <code>bool const status = QEQueue_post(eq, e, 0U, me->prio);
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QF_ACTIVE_DEFER, me->prio)
- QS_TIME_PRE_(); /* time stamp */
- QS_OBJ_PRE_(me); /* this active object */
- QS_OBJ_PRE_(eq); /* the deferred queue */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_END_PRE_()
- return status;</code>
- </operation>
- <!--${QF::QActive::recall}-->
- <operation name="recall" type="bool" visibility="0x01" properties="0x00">
- <documentation>/*! Recall a deferred event from a given event queue
- * @protected @memberof QActive
- *
- * @details
- * This function is part of the event deferral support. An active object
- * uses this function to recall a deferred event from a given QF
- * event queue. Recalling an event means that it is removed from the
- * deferred event queue `eq` and posted (LIFO) to the event queue of
- * the active object.
- *
- * @param[in] eq pointer to a "raw" thread-safe queue to recall
- * an event from.
- *
- * @returns
- * 'true' if an event has been recalled and 'false' if not.
- *
- * @note
- * An active object can use multiple event queues to defer events of
- * different kinds.
- *
- * @sa
- * QActive_recall(), QActive_postLIFO_(), ::QEQueue
- */
- /*! @protected @memberof QActive */</documentation>
- <!--${QF::QActive::recall::eq}-->
- <parameter name="eq" type="QEQueue * const"/>
- <code>QEvt const * const e = QEQueue_get(eq, me->prio);
- bool recalled;
- /* event available? */
- if (e != (QEvt *)0) {
- QF_CRIT_STAT_
- QACTIVE_POST_LIFO(me, e); /* post it to the front of the AO's queue */
- QF_CRIT_E_();
- /* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- /* after posting to the AO's queue the event must be referenced
- * at least twice: once in the deferred event queue (eq->get()
- * did NOT decrement the reference counter) and once in the
- * AO's event queue.
- */
- Q_ASSERT_CRIT_(210, e->refCtr_ >= 2U);
- /* we need to decrement the reference counter once, to account
- * for removing the event from the deferred event queue.
- */
- QEvt_refCtr_dec_(e); /* decrement the reference counter */
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_RECALL, me->prio)
- QS_TIME_PRE_(); /* time stamp */
- QS_OBJ_PRE_(me); /* this active object */
- QS_OBJ_PRE_(eq); /* the deferred queue */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_();
- recalled = true;
- }
- else {
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QF_ACTIVE_RECALL_ATTEMPT, me->prio)
- QS_TIME_PRE_(); /* time stamp */
- QS_OBJ_PRE_(me); /* this active object */
- QS_OBJ_PRE_(eq); /* the deferred queue */
- QS_END_PRE_()
- recalled = false;
- }
- return recalled;</code>
- </operation>
- <!--${QF::QActive::flushDeferred}-->
- <operation name="flushDeferred" type="uint_fast16_t" visibility="0x01" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! Flush the specified deferred queue 'eq'
- * @protected @memberof QActive
- *
- * @details
- * This function is part of the event deferral support. An active object
- * can use this function to flush a given QF event queue. The function
- * makes sure that the events are not leaked.
- *
- * @param[in] eq pointer to a "raw" thread-safe queue to flush.
- *
- * @returns
- * the number of events actually flushed from the queue.
- *
- * @sa
- * QActive_defer(), QActive_recall(), ::QEQueue
- */
- /*! @protected @memberof QActive */</documentation>
- <!--${QF::QActive::flushDeferred::eq}-->
- <parameter name="eq" type="QEQueue * const"/>
- <code>uint_fast16_t n = 0U;
- for (QEvt const *e = QEQueue_get(eq, me->prio);
- e != (QEvt *)0;
- e = QEQueue_get(eq, me->prio))
- {
- ++n; /* count the flushed event */
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e); /* garbage collect */
- #endif
- }
- return n;</code>
- </operation>
- <!--${QF::QActive::setAttr}-->
- <operation name="setAttr" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Generic setting of additional attributes (useful in QP ports)
- * @public @memberof QActive
- */
- /*! @public @memberof QActive */</documentation>
- <!--${QF::QActive::setAttr::attr1}-->
- <parameter name="attr1" type="uint32_t"/>
- <!--${QF::QActive::setAttr::attr2}-->
- <parameter name="attr2" type="void const *"/>
- </operation>
- <!--${QF::QActive::thread_}-->
- <operation name="thread_" type="void" visibility="0x02" properties="0x01">
- <documentation>/*! Thread routine for executing an active object `act`
- * @static @private @memberof QActive
- */
- /*! @static @private @memberof QActive */</documentation>
- <!--${QF::QActive::thread_::act}-->
- <parameter name="act" type="QActive *"/>
- </operation>
- <!--${QF::QActive::register_}-->
- <operation name="register_" type="void" visibility="0x01" properties="0x00">
- <documentation>/*! Register this active object to be managed by the framework
- * @protected @memberof QActive
- *
- * @details
- * This function adds a given active object to the active objects
- * managed by the QF framework. It should not be called by the
- * application directly, only through the function QActive::start().
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @precondition{qf_qact,100}
- * - the "QF-priority" of the AO must be in range (must be set
- * before calling QActive_register_())
- * - the "QF-priority" must not be already in use (unique priority)
- * - the "QF-priority" must not exceed the "preemption-threshold"
- *
- * @postcondition{qf_qact,190}
- * - the preceding pre-thre must not exceed the preemption-threshold
- * - the preemption-threshold must not exceed the next pre-thre
- *
- * @sa QActive_unregister_()
- */
- /*! @protected @memberof QActive */</documentation>
- <code>if (me->pthre == 0U) { /* preemption-threshold not defined? */
- me->pthre = me->prio; /* apply the default */
- }
- #ifndef Q_NASSERT
- Q_REQUIRE_ID(100, (0U < me->prio) && (me->prio <= QF_MAX_ACTIVE)
- && (QActive_registry_[me->prio] == (QActive *)0)
- && (me->prio <= me->pthre));
- uint8_t prev_thre = me->pthre;
- uint8_t next_thre = me->pthre;
- uint_fast8_t p;
- for (p = (uint_fast8_t)me->prio - 1U; p > 0U; --p) {
- if (QActive_registry_[p] != (QActive *)0) {
- prev_thre = QActive_registry_[p]->pthre;
- break;
- }
- }
- for (p = (uint_fast8_t)me->prio + 1U; p <= QF_MAX_ACTIVE; ++p) {
- if (QActive_registry_[p] != (QActive *)0) {
- next_thre = QActive_registry_[p]->pthre;
- break;
- }
- }
- Q_ENSURE_ID(190, (prev_thre <= me->pthre) && (me->pthre <= next_thre));
- #endif // Q_NASSERT
- QF_CRIT_STAT_
- QF_CRIT_E_();
- /* register the AO at the "QF-priority" */
- QActive_registry_[me->prio] = me;
- QF_CRIT_X_();</code>
- </operation>
- <!--${QF::QActive::unregister_}-->
- <operation name="unregister_" type="void" visibility="0x01" properties="0x00">
- <documentation>/*! Un-register the active object from the framework
- * @protected @memberof QActive
- *
- * @details
- * This function un-registers a given active object from the active objects
- * managed by the QF framework. It should not be called by the QP ports.
- *
- * @param[in] me pointer to the active object to remove from the
- * framework.
- *
- * @precondition{qf_qact,200}
- * - the priority of the active object must not be zero and cannot
- * exceed the maximum #QF_MAX_ACTIVE
- * - the priority of the AO must be already registered.
- *
- * @note
- * The active object that is removed from the framework can no longer
- * participate in any event exchange.
- *
- * @sa QActive_register_()
- */
- /*! @protected @memberof QActive */</documentation>
- <code>uint_fast8_t const p = (uint_fast8_t)me->prio;
- Q_REQUIRE_ID(200, (0U < p) && (p <= QF_MAX_ACTIVE)
- && (QActive_registry_[p] == me));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QActive_registry_[p] = (QActive *)0; /* free-up the priority level */
- me->super.state.fun = Q_STATE_CAST(0); /* invalidate the state */
- QF_CRIT_X_();</code>
- </operation>
- <!--${QF::QActive::postFromISR_}-->
- <operation name="postFromISR_?def QF_ISR_API" type="bool" visibility="0x02" properties="0x00">
- <documentation>/*! the "FromISR" variant used in the QP port to "FreeRTOS"
- * @private @memberof QActive
- */
- /*! @private @memberof QActive */</documentation>
- <!--${QF::QActive::postFromISR_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QF::QActive::postFromISR_::margin}-->
- <parameter name="margin" type="uint_fast16_t const"/>
- <!--${QF::QActive::postFromISR_::par}-->
- <parameter name="par" type="void *"/>
- <!--${QF::QActive::postFromISR_::sender}-->
- <parameter name="sender" type="void const * const"/>
- </operation>
- <!--${QF::QActive::publishFromISR_}-->
- <operation name="publishFromISR_?def QF_ISR_API" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! the "FromISR" variant used in the QP port to "FreeRTOS"
- * @static @private @memberof QActive
- */
- /*! @static @private @memberof QActive */</documentation>
- <!--${QF::QActive::publishFromISR_::e}-->
- <parameter name="e" type="QEvt const *"/>
- <!--${QF::QActive::publishFromISR_::par}-->
- <parameter name="par" type="void *"/>
- <!--${QF::QActive::publishFromISR_::sender}-->
- <parameter name="sender" type="void const *"/>
- </operation>
- </class>
- <!--${QF::QActiveVtable}-->
- <attribute name="QActiveVtable" type="typedef struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief Virtual table for the QActive class */</documentation>
- <code>{
- struct QHsmVtable super; /*!< @protected inherits ::QHsmVtable */
- /*! @private virtual function to start the AO/thread
- * @sa QACTIVE_START()
- */
- void (*start)(QActive * const me, QPrioSpec prio,
- QEvt const * * const qSto, uint_fast16_t const qLen,
- void * const stkSto, uint_fast16_t const stkSize,
- void const * const par);
- /*! @private virtual function to asynchronously post (FIFO)
- * an event to the AO
- * @sa QACTIVE_POST() and QACTIVE_POST_X()
- */
- bool (*post)(QActive * const me, QEvt const * const e,
- uint_fast16_t const margin, void const * const sender);
- /*! @private virtual function to asynchronously post (LIFO)
- * an event to the AO
- * @sa QACTIVE_POST_LIFO()
- */
- void (*postLIFO)(QActive * const me, QEvt const * const e);
- } QActiveVtable;</code>
- </attribute>
- <!--${QF::QMActive}-->
- <class name="QMActive" superclass="QF::QActive">
- <documentation>/*! @brief Active object class (based on QMsm implementation strategy)
- * @class QMActive
- * @extends QActive
- *
- * @details
- * ::QMActive represents an active object that uses the ::QMsm style state
- * machine implementation strategy. This strategy requires the use of the
- * QM modeling tool to generate state machine code automatically, but the
- * code is faster than in the ::QHsm style implementation strategy and needs
- * less run-time support (smaller event-processor).
- *
- * @note
- * ::QMActive is not intended to be instantiated directly, but rather serves
- * as the base class for derivation of active objects in the application.
- *
- * @trace
- * @tr{AQP214}
- *
- * @usage
- * The following example illustrates how to derive an active object from
- * ::QMActive. Please note that the ::QActive member @c super is defined as
- * the **first** member of the derived struct (see @ref oop).
- * @include qf_qmactive.c
- */</documentation>
- <!--${QF::QMActive::ctor}-->
- <operation name="ctor" type="void" visibility="0x01" properties="0x00">
- <documentation>/*! Constructor of ::QMActive class.
- * @protected @memberof QMActive
- *
- * @details
- * Performs the first step of active object initialization by assigning
- * the virtual pointer and calling the superclass constructor.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] initial pointer to the event to be dispatched to the MSM
- *
- * @note Must be called only ONCE before QHSM_INIT().
- *
- * @sa QHsm_ctor()
- */
- /*! @protected @memberof QMActive */</documentation>
- <!--${QF::QMActive::ctor::initial}-->
- <parameter name="initial" type="QStateHandler const"/>
- <code>static QMActiveVtable const vtable = { /* QMActive virtual table */
- { &QMsm_init_,
- &QMsm_dispatch_
- #ifdef Q_SPY
- ,&QMsm_getStateHandler_
- #endif
- },
- &QActive_start_,
- &QActive_post_,
- &QActive_postLIFO_
- };
- /* clear the whole QMActive object, so that the framework can start
- * correctly even if the startup code fails to clear the uninitialized
- * data (as is required by the C Standard).
- */
- QF_bzero(me, sizeof(*me));
- /*!
- * @note
- * ::QMActive inherits ::QActive, so by the @ref oop convention
- * it should call the constructor of the superclass, i.e., QActive_ctor().
- * However, this would pull in the QActiveVtable, which in turn will pull
- * in the code for QHsm_init_() and QHsm_dispatch_() implemetations,
- * which is expensive. To avoid this code size penalty, in case QHsm is
- * not used in a given project, the call to QMsm_ctor() avoids pulling
- * in the code for QHsm.
- */
- QMsm_ctor(QMSM_CAST_(&me->super.super), initial);
- me->super.super.vptr = &vtable.super; /* hook vptr to QMActive vtable */</code>
- </operation>
- </class>
- <!--${QF::QMActiveVtable}-->
- <attribute name="QMActiveVtable" type="typedef QActiveVtable" visibility="0x04" properties="0x00">
- <documentation>/*! @brief Virtual Table for the ::QMActive class (inherited
- * from ::QActiveVtable)
- *
- * @note
- * ::QMActive inherits ::QActive exactly, without adding any new virtual
- * functions and therefore, ::QMActiveVtable is typedef'ed as ::QActiveVtable.
- */</documentation>
- </attribute>
- <!--${QF::QTimeEvt}-->
- <class name="QTimeEvt" superclass="QEP::QEvt">
- <documentation>/*! @brief Time Event class
- * @class QTimeEvt
- * @extends QEvt
- *
- * @details
- * Time events are special QF events equipped with the notion of time passage.
- * The basic usage model of the time events is as follows. An active object
- * allocates one or more ::QTimeEvt objects (provides the storage for them).
- * When the active object needs to arrange for a timeout, it arms one of its
- * time events to fire either just once (one-shot) or periodically. Each time
- * event times out independently from the others, so a QF application can make
- * multiple parallel timeout requests (from the same or different active
- * objects). When QF detects that the appropriate moment has arrived, it
- * inserts the time event directly into the recipient's event queue. The
- * recipient then processes the time event just like any other event.
- *
- * Time events, as any other QF events derive from the ::QEvt base class.
- * Typically, you will use a time event as-is, but you can also further
- * derive more specialized time events from it by adding some more data
- * members and/or specialized functions that operate on the specialized
- * time events.
- *
- * Internally, the armed time events are organized into linked lists--one
- * list for every supported ticking rate. These linked lists are scanned in
- * every invocation of the QTIMEEVT_TICK_X() macro. Only armed (timing out)
- * time events are in the list, so only armed time events consume CPU cycles.
- *
- * @sa ::QTimeEvt for the description of the data members
- *
- * @trace
- * @tr{AQP215}
- *
- * @note
- * QF manages the time events in the QTIMEEVT_TICK_X() macro, which must
- * be called periodically, from the clock tick ISR or from other periodic
- * source. QTIMEEVT_TICK_X() caYou might also use the special ::QTicker
- * active object.
- *
- * @note
- * Even though ::QTimeEvt is a subclass of ::QEvt, ::QTimeEvt instances can NOT
- * be allocated dynamically from event pools. In other words, it is illegal to
- * allocate ::QTimeEvt instances with the Q_NEW() or Q_NEW_X() macros.
- */</documentation>
- <!--${QF::QTimeEvt::next}-->
- <attribute name="next" type="struct QTimeEvt * volatile" visibility="0x02" properties="0x00">
- <documentation>/*! link to the next time event in the list
- * @private @memberof QTimeEvt
- */</documentation>
- </attribute>
- <!--${QF::QTimeEvt::act}-->
- <attribute name="act" type="void * volatile" visibility="0x02" properties="0x00">
- <documentation>/*! The active object that receives the time events
- * @private @memberof QTimeEvt
- */</documentation>
- </attribute>
- <!--${QF::QTimeEvt::ctr}-->
- <attribute name="ctr" type="QTimeEvtCtr volatile" visibility="0x02" properties="0x00">
- <documentation>/*! Internal down-counter of the time event.
- * @private @memberof QTimeEvt
- *
- * @details
- * The down-counter is decremented by 1 in every QTimeEvt_tick_() call.
- * The time event fires (gets posted or published) when the down-counter
- * reaches zero.
- */</documentation>
- </attribute>
- <!--${QF::QTimeEvt::interval}-->
- <attribute name="interval" type="QTimeEvtCtr" visibility="0x02" properties="0x00">
- <documentation>/*! Interval for periodic time event (zero for one-shot time event)
- * @private @memberof QTimeEvt
- *
- * @details
- * The value of the interval is re-loaded to the internal down-counter
- * when the time event expires, so that the time event keeps timing out
- * periodically.
- */</documentation>
- </attribute>
- <!--${QF::QTimeEvt::timeEvtHead_[QF_MAX_TICK_RATE]}-->
- <attribute name="timeEvtHead_[QF_MAX_TICK_RATE]" type="QTimeEvt" visibility="0x00" properties="0x01">
- <documentation>/*! heads of linked lists of time events, one for every clock tick rate */</documentation>
- </attribute>
- <!--${QF::QTimeEvt::ctorX}-->
- <operation name="ctorX" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! The "extended" constructor to initialize a Time Event.
- * @public @memberof QTimeEvt
- *
- * @details
- * When creating a time event, you must commit it to a specific active object
- * `act`, tick rate `tickRate` and event signal `sig`. You cannot change
- * these attributes later.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] act pointer to the active object associated with this
- * time event. The time event will post itself to this AO.
- * @param[in] sig signal to associate with this time event.
- * @param[in] tickRate system clock tick rate to associate with this
- * time event in the range [0..15].
- *
- * @precondition{qf_time,300}
- * - the signal `sig` must be valid
- * - the tick rate `tickRate` must be in range
- *
- * @note
- * You should call QTimeEvt_ctorX() exactly once for every Time Event
- * object **before** arming the Time Event. The ideal place for calling
- * QTimeEvt_ctorX() is the constructor of the associated AO.
- */
- /*! @public @memberof QTimeEvt */</documentation>
- <!--${QF::QTimeEvt::ctorX::act}-->
- <parameter name="act" type="QActive * const"/>
- <!--${QF::QTimeEvt::ctorX::sig}-->
- <parameter name="sig" type="enum_t const"/>
- <!--${QF::QTimeEvt::ctorX::tickRate}-->
- <parameter name="tickRate" type="uint_fast8_t const"/>
- <code>Q_REQUIRE_ID(300, (sig != 0)
- && (tickRate < QF_MAX_TICK_RATE));
- me->next = (QTimeEvt *)0;
- me->ctr = 0U;
- me->interval = 0U;
- me->super.sig = (QSignal)sig;
- /* For backwards compatibility with the deprecated QTimeEvt_ctor(),
- * the active object pointer `act` can be uninitialized (NULL) and is
- * NOT validated in the precondition. The active object pointer is
- * validated in preconditions to QTimeEvt_armX() and QTimeEvt_rearm().
- */
- me->act = act;
- /* Setting the POOL_ID event attribute to zero is correct only for
- * events not allocated from event pools, which must be the case
- * for Time Events.
- */
- me->super.poolId_ = 0U;
- /* The refCtr_ attribute is not used in time events, so it is
- * reused to hold the tickRate as well as other information
- */
- me->super.refCtr_ = (uint8_t)tickRate;</code>
- </operation>
- <!--${QF::QTimeEvt::armX}-->
- <operation name="armX" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Arm a time event (one shot or periodic) for direct event posting.
- * @public @memberof QTimeEvt
- *
- * @details
- * Arms a time event to fire in a specified number of clock ticks and with
- * a specified interval. If the interval is zero, the time event is armed for
- * one shot ('one-shot' time event). When the timeout expires, the time event
- * gets directly posted (using the FIFO policy) into the event queue of the
- * host active object. After posting, a one-shot time event gets automatically
- * disarmed while a periodic time event (interval != 0) is automatically
- * re-armed.
- *
- * A time event can be disarmed at any time by calling QTimeEvt_disarm().
- * Also, a time event can be re-armed to fire in a different number of clock
- * ticks by calling the QTimeEvt_rearm().
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] nTicks number of clock ticks (at the associated rate)
- * to rearm the time event with.
- * @param[in] interval interval (in clock ticks) for periodic time event.
- *
- * @precondition{qf_time,400}
- * - the host AO must be valid,
- * - the time eveht must be disarmed,
- * - the number of clock ticks cannot be zero,
- * - the signal must be valid.
- *
- * @attention
- * Arming an already armed time event is __not__ allowed and is considered
- * a programming error. The QP/C framework will assert if it detects an
- * attempt to arm an already armed time event.
- *
- * @usage
- * The following example shows how to arm a periodic time event as well as
- * one-shot time event from a state machine of an active object:
- * @include qf_tevt.c
- */
- /*! @public @memberof QTimeEvt */</documentation>
- <!--${QF::QTimeEvt::armX::nTicks}-->
- <parameter name="nTicks" type="QTimeEvtCtr const"/>
- <!--${QF::QTimeEvt::armX::interval}-->
- <parameter name="interval" type="QTimeEvtCtr const"/>
- <code>uint_fast8_t const tickRate
- = ((uint_fast8_t)me->super.refCtr_ & QTE_TICK_RATE);
- QTimeEvtCtr const ctr = me->ctr;
- #ifdef Q_SPY
- uint_fast8_t const qs_id = ((QActive *)(me->act))->prio;
- #endif
- Q_REQUIRE_ID(400, (me->act != (void *)0)
- && (ctr == 0U)
- && (nTicks != 0U)
- && (tickRate < (uint_fast8_t)QF_MAX_TICK_RATE)
- && (me->super.sig >= (QSignal)Q_USER_SIG));
- #ifdef Q_NASSERT
- Q_UNUSED_PAR(ctr);
- #endif
- QF_CRIT_STAT_
- QF_CRIT_E_();
- me->ctr = nTicks;
- me->interval = interval;
- /* is the time event unlinked?
- * NOTE: For the duration of a single clock tick of the specified tick
- * rate a time event can be disarmed and yet still linked into the list,
- * because un-linking is performed exclusively in QTimeEvt_tick_().
- */
- if ((me->super.refCtr_ & QTE_IS_LINKED) == 0U) {
- me->super.refCtr_ |= QTE_IS_LINKED; /* mark as linked */
- /* The time event is initially inserted into the separate
- * "freshly armed" link list based on QTimeEvt_timeEvtHead_[tickRate].act.
- * Only later, inside the QTimeEvt_tick_() function, the "freshly armed"
- * list is appended to the main list of armed time events based on
- * QTimeEvt_timeEvtHead_[tickRate].next. Again, this is to keep any
- * changes to the main list exclusively inside the QTimeEvt_tick_()
- * function.
- */
- me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
- QTimeEvt_timeEvtHead_[tickRate].act = me;
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_ARM, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this time event object */
- QS_OBJ_PRE_(me->act); /* the active object */
- QS_TEC_PRE_(nTicks); /* the number of ticks */
- QS_TEC_PRE_(interval); /* the interval */
- QS_U8_PRE_(tickRate); /* tick rate */
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_();</code>
- </operation>
- <!--${QF::QTimeEvt::disarm}-->
- <operation name="disarm" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! Disarm a time event.
- * @public @memberof QTimeEvt
- *
- * @details
- * Disarm the time event so it can be safely reused.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @returns
- * 'true' if the time event was truly disarmed, that is, it was running.
- * The return of 'false' means that the time event was not truly disarmed,
- * because it was not running. The 'false' return is only possible for one-
- * shot time events that have been automatically disarmed upon expiration.
- * In this case the 'false' return means that the time event has already
- * been posted or published and should be expected in the active object's
- * state machine.
- *
- * @note
- * there is no harm in disarming an already disarmed time event
- */
- /*! @public @memberof QTimeEvt */</documentation>
- <code>#ifdef Q_SPY
- uint_fast8_t const qs_id = QACTIVE_CAST_(me->act)->prio;
- #endif
- QF_CRIT_STAT_
- QF_CRIT_E_();
- /* is the time event actually armed? */
- bool wasArmed;
- if (me->ctr != 0U) {
- wasArmed = true;
- me->super.refCtr_ |= QTE_WAS_DISARMED;
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_DISARM, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this time event object */
- QS_OBJ_PRE_(me->act); /* the target AO */
- QS_TEC_PRE_(me->ctr); /* the number of ticks */
- QS_TEC_PRE_(me->interval); /* the interval */
- QS_U8_PRE_(me->super.refCtr_ & QTE_TICK_RATE);
- QS_END_NOCRIT_PRE_()
- me->ctr = 0U; /* schedule removal from the list */
- }
- else { /* the time event was already disarmed automatically */
- wasArmed = false;
- me->super.refCtr_ &= (uint8_t)(~QTE_WAS_DISARMED & 0xFFU);
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_DISARM_ATTEMPT, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this time event object */
- QS_OBJ_PRE_(me->act); /* the target AO */
- QS_U8_PRE_(me->super.refCtr_ & QTE_TICK_RATE);
- QS_END_NOCRIT_PRE_()
- }
- QF_CRIT_X_();
- return wasArmed;</code>
- </operation>
- <!--${QF::QTimeEvt::rearm}-->
- <operation name="rearm" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! Rearm a time event.
- * @public @memberof QTimeEvt
- *
- * @details
- * Rearms a time event with a new number of clock ticks. This function can
- * be used to adjust the current period of a periodic time event or to
- * prevent a one-shot time event from expiring (e.g., a watchdog time event).
- * Rearming a periodic timer leaves the interval unchanged and is a convenient
- * method to adjust the phasing of a periodic time event.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] nTicks number of clock ticks (at the associated rate)
- * to rearm the time event with.
- *
- * @returns
- * 'true' if the time event was running as it was re-armed. The 'false'
- * return means that the time event was not truly rearmed because it was
- * not running. The 'false' return is only possible for one-shot time events
- * that have been automatically disarmed upon expiration. In this case the
- * 'false' return means that the time event has already been posted or
- * published and should be expected in the active object's state machine.
- *
- * @precondition{qf_time,600}
- * - AO must be valid
- * - tick rate must be in range
- * - nTicks must not be zero,
- * - the signal of this time event must be valid
- */
- /*! @public @memberof QTimeEvt */</documentation>
- <!--${QF::QTimeEvt::rearm::nTicks}-->
- <parameter name="nTicks" type="QTimeEvtCtr const"/>
- <code>uint_fast8_t const tickRate
- = (uint_fast8_t)me->super.refCtr_ & QTE_TICK_RATE;
- #ifdef Q_SPY
- uint_fast8_t const qs_id = ((QActive *)(me->act))->prio;
- #endif
- Q_REQUIRE_ID(600, (me->act != (void *)0)
- && (tickRate < QF_MAX_TICK_RATE)
- && (nTicks != 0U)
- && (me->super.sig >= (QSignal)Q_USER_SIG));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- /* is the time evt not running? */
- bool wasArmed;
- if (me->ctr == 0U) {
- wasArmed = false;
- /* NOTE: For the duration of a single clock tick of the specified
- * tick rate a time event can be disarmed and yet still linked into
- * the list, because unlinking is performed exclusively in the
- * QTimeEvt_tick_() function.
- */
- /* is the time event linked yet? */
- if ((me->super.refCtr_ & QTE_IS_LINKED) == 0U) {
- me->super.refCtr_ |= QTE_IS_LINKED; /* mark as linked */
- /* The time event is initially inserted into the separate
- * "freshly armed" list based on QTimeEvt_timeEvtHead_[tickRate].act.
- * Only later, inside the QTimeEvt_tick_() function, the "freshly
- * armed" list is appended to the main list of armed time events
- * based on QTimeEvt_timeEvtHead_[tickRate].next. Again, this is
- * to keep any changes to the main list exclusively inside the
- * QTimeEvt_tick_() function.
- */
- me->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
- QTimeEvt_timeEvtHead_[tickRate].act = me;
- }
- }
- else { /* the time event was armed */
- wasArmed = true;
- }
- me->ctr = nTicks; /* re-load the tick counter (shift the phasing) */
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_REARM, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this time event object */
- QS_OBJ_PRE_(me->act); /* the target AO */
- QS_TEC_PRE_(me->ctr); /* the number of ticks */
- QS_TEC_PRE_(me->interval); /* the interval */
- QS_2U8_PRE_(tickRate, (wasArmed ? 1U : 0U));
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_();
- return wasArmed;</code>
- </operation>
- <!--${QF::QTimeEvt::wasDisarmed}-->
- <operation name="wasDisarmed" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! Check the "was disarmed" status of a time event.
- * @public @memberof QTimeEvt
- *
- * @details
- * Useful for checking whether a one-shot time event was disarmed in the
- * QTimeEvt_disarm() operation.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @returns
- * 'true' if the time event was truly disarmed in the last QTimeEvt_disarm()
- * operation. The 'false' return means that the time event was not truly
- * disarmed, because it was not running at that time. The 'false' return is
- * only possible for one-shot time events that have been automatically disarmed
- * upon expiration. In this case the 'false' return means that the time event
- * has already been posted or published and should be expected in the active
- * object's event queue.
- *
- * @note
- * This function has a **side effect** of setting the "was disarmed" status,
- * which means that the second and subsequent times this function is called
- * the function will return 'true'.
- */
- /*! @public @memberof QTimeEvt */</documentation>
- <code>uint8_t const wasDisarmed = (me->super.refCtr_ & QTE_WAS_DISARMED);
- me->super.refCtr_ |= QTE_WAS_DISARMED; /* mark as disarmed */
- return wasDisarmed != 0U;</code>
- </operation>
- <!--${QF::QTimeEvt::currCtr}-->
- <operation name="currCtr" type="QTimeEvtCtr" visibility="0x00" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! Get the current value of the down-counter of a time event.
- * @public @memberof QTimeEvt
- *
- * @details
- * Useful for checking how many clock ticks (at the tick rate associated
- * with the time event) remain until the time event expires.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @returns
- * For an armed time event, the function returns the current value of the
- * down-counter of the given time event. If the time event is not armed,
- * the function returns 0.
- *
- * @note
- * The function is thread-safe.
- */
- /*! @public @memberof QTimeEvt */</documentation>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QTimeEvtCtr const ret = me->ctr;
- QF_CRIT_X_();
- return ret;</code>
- </operation>
- <!--${QF::QTimeEvt::tick_}-->
- <operation name="tick_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Processes all armed time events at every clock tick.
- * @static @private @memberof QTimeEvt
- *
- * @details
- * This internal helper function processes all armed ::QTimeEvt objects
- * associated wit the tick rate `tickRate`.
- *
- * This function must be called periodically from a time-tick ISR or from
- * a task so that QF can manage the timeout events assigned to the given
- * system clock tick rate.
- *
- * @param[in] tickRate clock tick rate serviced in this call [1..15].
- * @param[in] sender pointer to a sender object (only for QS tracing)
- *
- * @note
- * this function should be called only via the macro QTIMEEVT_TICK_X()
- *
- * @note
- * the calls to QTimeEvt_tick_() with different `tickRate` parameter can
- * preempt each other. For example, higher clock tick rates might be
- * serviced from interrupts while others from tasks (active objects).
- *
- * @sa ::QTimeEvt.
- */
- /*! @static @private @memberof QTimeEvt */</documentation>
- <!--${QF::QTimeEvt::tick_::tickRate}-->
- <parameter name="tickRate" type="uint_fast8_t const"/>
- <!--${QF::QTimeEvt::tick_::sender}-->
- <parameter name="sender" type="void const * const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(sender);
- #endif
- QTimeEvt *prev = &QTimeEvt_timeEvtHead_[tickRate];
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TICK, 0U)
- ++prev->ctr;
- QS_TEC_PRE_(prev->ctr); /* tick ctr */
- QS_U8_PRE_(tickRate); /* tick rate */
- QS_END_NOCRIT_PRE_()
- /* scan the linked-list of time events at this rate... */
- for (;;) {
- QTimeEvt *t = prev->next; /* advance down the time evt. list */
- /* end of the list? */
- if (t == (QTimeEvt *)0) {
- /* any new time events armed since the last QTimeEvt_tick_()? */
- if (QTimeEvt_timeEvtHead_[tickRate].act != (void *)0) {
- /* sanity check */
- Q_ASSERT_CRIT_(110, prev != (QTimeEvt *)0);
- prev->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
- QTimeEvt_timeEvtHead_[tickRate].act = (void *)0;
- t = prev->next; /* switch to the new list */
- }
- else {
- break; /* all currently armed time evts. processed */
- }
- }
- /* time event scheduled for removal? */
- if (t->ctr == 0U) {
- prev->next = t->next;
- /* mark time event 't' as NOT linked */
- t->super.refCtr_ &= (uint8_t)(~QTE_IS_LINKED & 0xFFU);
- /* do NOT advance the prev pointer */
- QF_CRIT_X_(); /* exit crit. section to reduce latency */
- /* prevent merging critical sections, see NOTE1 below */
- QF_CRIT_EXIT_NOP();
- }
- else {
- --t->ctr;
- /* is time event about to expire? */
- if (t->ctr == 0U) {
- QActive * const act = (QActive *)t->act;
- /* periodic time evt? */
- if (t->interval != 0U) {
- t->ctr = t->interval; /* rearm the time event */
- prev = t; /* advance to this time event */
- }
- /* one-shot time event: automatically disarm */
- else {
- prev->next = t->next;
- /* mark time event 't' as NOT linked */
- t->super.refCtr_ &= (uint8_t)(~QTE_IS_LINKED & 0xFFU);
- /* do NOT advance the prev pointer */
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_AUTO_DISARM, act->prio)
- QS_OBJ_PRE_(t); /* this time event object */
- QS_OBJ_PRE_(act); /* the target AO */
- QS_U8_PRE_(tickRate); /* tick rate */
- QS_END_NOCRIT_PRE_()
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_POST, act->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(t); /* the time event object */
- QS_SIG_PRE_(t->super.sig); /* signal of this time event */
- QS_OBJ_PRE_(act); /* the target AO */
- QS_U8_PRE_(tickRate); /* tick rate */
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_(); /* exit critical section before posting */
- /* QACTIVE_POST() asserts internally if the queue overflows */
- QACTIVE_POST(act, &t->super, sender);
- }
- else {
- prev = t; /* advance to this time event */
- QF_CRIT_X_(); /* exit crit. section to reduce latency */
- /* prevent merging critical sections
- * In some QF ports the critical section exit takes effect only
- * on the next machine instruction. If this case, the next
- * instruction is another entry to a critical section, the
- * critical section won't be really exited, but rather the
- * two adjacent critical sections would be merged. The
- * QF_CRIT_EXIT_NOP() macro contains minimal code required
- * to prevent such merging of critical sections in QF ports,
- * in which it can occur.
- */
- QF_CRIT_EXIT_NOP();
- }
- }
- QF_CRIT_E_(); /* re-enter crit. section to continue */
- }
- QF_CRIT_X_();</code>
- </operation>
- <!--${QF::QTimeEvt::tick1_}-->
- <operation name="tick1_?def Q_UTEST" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Processes one clock tick for QUTest
- * @static @private @memberof QTimeEvt
- */
- /*! @static @private @memberof QTimeEvt */</documentation>
- <!--${QF::QTimeEvt::tick1_::tickRate}-->
- <parameter name="tickRate" type="uint_fast8_t const"/>
- <!--${QF::QTimeEvt::tick1_::sender}-->
- <parameter name="sender" type="void const * const"/>
- </operation>
- <!--${QF::QTimeEvt::noActive}-->
- <operation name="noActive" type="bool" visibility="0x00" properties="0x01">
- <documentation>/*! Returns 'true' if there are no armed time events at a given tick rate.
- * @static @public @memberof QTimeEvt
- *
- * @details
- * Find out if any time events are armed at the given clock tick rate.
- *
- * @param[in] tickRate system clock tick rate to find out about.
- *
- * @returns
- * 'true' if no time events are armed at the given tick rate and
- * 'false' otherwise.
- *
- * @precondition{qf_time,800}
- * - the tick rate must be in range
- *
- * @note
- * This function should be called in critical section.
- */
- /*! @static @public @memberof QTimeEvt */</documentation>
- <!--${QF::QTimeEvt::noActive::tickRate}-->
- <parameter name="tickRate" type="uint_fast8_t const"/>
- <code>Q_REQUIRE_ID(800, tickRate < QF_MAX_TICK_RATE);
- bool inactive;
- if (QTimeEvt_timeEvtHead_[tickRate].next != (QTimeEvt *)0) {
- inactive = false;
- }
- else if ((QTimeEvt_timeEvtHead_[tickRate].act != (void *)0)) {
- inactive = false;
- }
- else {
- inactive = true;
- }
- return inactive;</code>
- </operation>
- </class>
- <!--${QF::QTicker}-->
- <class name="QTicker" superclass="QF::QActive">
- <documentation>/*! @brief "Ticker" Active Object class
- * @class QTicker
- * @extends QActive
- *
- * @details
- * QTicker is an efficient active object specialized to process QF system
- * clock tick at a specified tick rate [0..#QF_MAX_TICK_RATE].
- * Placing system clock tick processing in an active object allows you
- * to remove the non-deterministic QTIMEEVT_TICK_X() processing from the
- * interrupt level and move it into the thread-level, where you can prioritize
- * it as low as you wish.
- *
- * @usage
- * The following example illustrates use of QTicker active objects:
- * @include qf_ticker.c
- */</documentation>
- <!--${QF::QTicker::ctor}-->
- <operation name="ctor" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Constructor of the QTicker Active Object class
- * @public @memberof QTicker
- */
- /*! @public @memberof QTicker */</documentation>
- <!--${QF::QTicker::ctor::tickRate}-->
- <parameter name="tickRate" type="uint_fast8_t const"/>
- <code>static QActiveVtable const vtable = { /* QActive virtual table */
- { &QTicker_init_,
- &QTicker_dispatch_
- #ifdef Q_SPY
- ,&QHsm_getStateHandler_
- #endif
- },
- &QActive_start_,
- &QTicker_post_,
- &QTicker_postLIFO_
- };
- QActive_ctor(&me->super, Q_STATE_CAST(0)); /* superclass' ctor */
- me->super.super.vptr = &vtable.super; /* hook the vptr */
- /* reuse eQueue.head for tick-rate */
- me->super.eQueue.head = (QEQueueCtr)tickRate;</code>
- </operation>
- <!--${QF::QTicker::init_}-->
- <operation name="init_" type="void" visibility="0x02" properties="0x01">
- <documentation>/*! initialization (override)
- * @private @memberof QTicker
- */
- /*! @private @memberof QTicker */</documentation>
- <!--${QF::QTicker::init_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QF::QTicker::init_::par}-->
- <parameter name="par" type="void const * const"/>
- <!--${QF::QTicker::init_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>Q_UNUSED_PAR(me);
- Q_UNUSED_PAR(par);
- Q_UNUSED_PAR(qs_id);
- QTICKER_CAST_(me)->eQueue.tail = 0U;</code>
- </operation>
- <!--${QF::QTicker::dispatch_}-->
- <operation name="dispatch_" type="void" visibility="0x02" properties="0x01">
- <documentation>/*! dispatching (override)
- * @private @memberof QTicker
- */
- /*! @private @memberof QTicker */</documentation>
- <!--${QF::QTicker::dispatch_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QF::QTicker::dispatch_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QF::QTicker::dispatch_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>Q_UNUSED_PAR(e);
- Q_UNUSED_PAR(qs_id);
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QEQueueCtr nTicks = QTICKER_CAST_(me)->eQueue.tail; /* save # of ticks */
- QTICKER_CAST_(me)->eQueue.tail = 0U; /* clear # ticks */
- QF_CRIT_X_();
- for (; nTicks > 0U; --nTicks) {
- QTimeEvt_tick_((uint_fast8_t)QTICKER_CAST_(me)->eQueue.head, me);
- }</code>
- </operation>
- <!--${QF::QTicker::post_}-->
- <operation name="post_" type="bool" visibility="0x00" properties="0x01">
- <documentation>/*! post (override)
- * @private @memberof QTicker
- */
- /*! @private @memberof QTicker */</documentation>
- <!--${QF::QTicker::post_::me}-->
- <parameter name="me" type="QActive * const"/>
- <!--${QF::QTicker::post_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QF::QTicker::post_::margin}-->
- <parameter name="margin" type="uint_fast16_t const"/>
- <!--${QF::QTicker::post_::sender}-->
- <parameter name="sender" type="void const * const"/>
- <code>Q_UNUSED_PAR(e);
- Q_UNUSED_PAR(margin);
- #ifndef Q_SPY
- Q_UNUSED_PAR(sender);
- #endif
- QF_CRIT_STAT_
- QF_CRIT_E_();
- if (me->eQueue.frontEvt == (QEvt *)0) {
- static QEvt const tickEvt = { 0U, 0U, 0U };
- me->eQueue.frontEvt = &tickEvt; /* deliver event directly */
- --me->eQueue.nFree; /* one less free event */
- QACTIVE_EQUEUE_SIGNAL_(me); /* signal the event queue */
- }
- ++me->eQueue.tail; /* account for one more tick event */
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(sender); /* the sender object */
- QS_SIG_PRE_(0U); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this active object */
- QS_2U8_PRE_(0U, 0U); /* pool Id & refCtr of the evt */
- QS_EQC_PRE_(0U); /* number of free entries */
- QS_EQC_PRE_(0U); /* min number of free entries */
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_();
- return true; /* the event is always posted correctly */</code>
- </operation>
- <!--${QF::QTicker::postLIFO_}-->
- <operation name="postLIFO_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! post-LIFO (override)
- * @private @memberof QTicker
- */
- /*! @private @memberof QTicker */</documentation>
- <!--${QF::QTicker::postLIFO_::me}-->
- <parameter name="me" type="QActive * const"/>
- <!--${QF::QTicker::postLIFO_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <code>Q_UNUSED_PAR(me);
- Q_UNUSED_PAR(e);
- Q_ERROR_ID(900);</code>
- </operation>
- </class>
- <!--${QF::QEQueue}-->
- <class name="QEQueue">
- <documentation>/*! @brief Native QF Event Queue
- * @class QEQueue
- *
- * @details
- * This class describes the native QF event queue, which can be used as
- * the event queue for active objects, or as a simple "raw" event queue for
- * thread-safe event passing among non-framework entities, such as ISRs,
- * device drivers, or other third-party components.<br>
- *
- * The native QF event queue is configured by defining the macro
- * #QF_EQUEUE_TYPE as ::QEQueue in the specific QF port header file.<br>
- * <br>
- * The ::QEQueue structure contains only data members for managing an event
- * queue, but does not contain the storage for the queue buffer, which must
- * be provided externally during the queue initialization.<br>
- * <br>
- * The event queue can store only event pointers, not the whole events. The
- * internal implementation uses the standard ring-buffer plus one external
- * location that optimizes the queue operation for the most frequent case
- * of empty queue.<br>
- * <br>
- * The ::QEQueue structure is used with two sets of functions. One set is for
- * the active object event queue, which might need to block the active object
- * task when the event queue is empty and might need to unblock it when
- * events are posted to the queue. The interface for the native active object
- * event queue consists of the following functions: QActive_post(),
- * QActive_postLIFO(), and QActive_get_(). Additionally the function
- * QEQueue_init() is used to initialize the queue.<br>
- * <br>
- * The other set of functions, uses ::QEQueue as a simple "raw" event
- * queue to pass events between entities other than active objects, such as
- * ISRs. The "raw" event queue is not capable of blocking on the get()
- * operation, but is still thread-safe because it uses QF critical section
- * to protect its integrity. The interface for the "raw" thread-safe queue
- * consists of the following functions: QEQueue_post(),
- * QEQueue_postLIFO(), and QEQueue_get(). Additionally the function
- * QEQueue_init() is used to initialize the queue.
- *
- * <br>ote Most event queue operations (both the active object queues and
- * the "raw" queues) internally use the QF critical section. You should be
- * careful not to invoke those operations from other critical sections when
- * nesting of critical sections is not supported.
- *
- * @sa ::QEQueue for the description of the data members
- */</documentation>
- <!--${QF::QEQueue::frontEvt}-->
- <attribute name="frontEvt" type="QEvt const * volatile" visibility="0x02" properties="0x00">
- <documentation>/*! pointer to event at the front of the queue.
- * @private @memberof QEQueue
- *
- * @details
- * All incoming and outgoing events pass through the frontEvt location.
- * When the queue is empty (which is most of the time), the extra
- * frontEvt location allows to bypass the ring buffer altogether,
- * greatly optimizing the performance of the queue. Only bursts of events
- * engage the ring buffer.
- *
- * <br>ote The additional role of this attribute is to indicate the empty
- * status of the queue. The queue is empty when frontEvt is NULL.
- */</documentation>
- </attribute>
- <!--${QF::QEQueue::ring}-->
- <attribute name="ring" type="QEvt const **" visibility="0x02" properties="0x00">
- <documentation>/*! pointer to the start of the ring buffer
- * @private @memberof QEQueue
- */</documentation>
- </attribute>
- <!--${QF::QEQueue::end}-->
- <attribute name="end" type="QEQueueCtr" visibility="0x02" properties="0x00">
- <documentation>/*! offset of the end of the ring buffer from the start of the buffer
- * @private @memberof QEQueue
- */</documentation>
- </attribute>
- <!--${QF::QEQueue::head}-->
- <attribute name="head" type="QEQueueCtr volatile" visibility="0x02" properties="0x00">
- <documentation>/*! offset to where next event will be inserted into the buffer
- * @private @memberof QEQueue
- */</documentation>
- </attribute>
- <!--${QF::QEQueue::tail}-->
- <attribute name="tail" type="QEQueueCtr volatile" visibility="0x02" properties="0x00">
- <documentation>/*! offset of where next event will be extracted from the buffer
- * @private @memberof QEQueue
- */</documentation>
- </attribute>
- <!--${QF::QEQueue::nFree}-->
- <attribute name="nFree" type="QEQueueCtr volatile" visibility="0x02" properties="0x00">
- <documentation>/*! number of free events in the ring buffer
- * @private @memberof QEQueue
- */</documentation>
- </attribute>
- <!--${QF::QEQueue::nMin}-->
- <attribute name="nMin" type="QEQueueCtr" visibility="0x02" properties="0x00">
- <documentation>/*! Minimum number of free events ever in the ring buffer.
- * @private @memberof QEQueue
- *
- * @details
- * This attribute remembers the low-watermark of the ring buffer,
- * which provides a valuable information for sizing event queues.
- * @sa QF_getQueueMargin().
- */</documentation>
- </attribute>
- <!--${QF::QEQueue::init}-->
- <operation name="init" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Initialize the native QF event queue.
- * @public @memberof QEQueue
- *
- * @details
- * Initialize the event queue by giving it the storage for the ring buffer.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] qSto an array of pointers to ::QEvt to sereve as the
- * ring buffer for the event queue
- * @param[in] qLen the length of the `qSto` buffer (in ::QEvt pointers)
- *
- * @note The actual capacity of the queue is qLen + 1, because of the extra
- * location forntEvt.
- *
- * @note
- * This function is also used to initialize the event queues of active
- * objects in the built-int QV and QK kernels, as well as other
- * QP ports to OSes/RTOSes that do provide a suitable message queue.
- */
- /*! @public @memberof QEQueue */</documentation>
- <!--${QF::QEQueue::init::qSto}-->
- <parameter name="qSto" type="QEvt const ** const"/>
- <!--${QF::QEQueue::init::qLen}-->
- <parameter name="qLen" type="uint_fast16_t const"/>
- <code>me->frontEvt = (QEvt *)0; /* no events in the queue */
- me->ring = qSto; /* the beginning of the ring buffer */
- me->end = (QEQueueCtr)qLen;
- if (qLen != 0U) {
- me->head = 0U;
- me->tail = 0U;
- }
- me->nFree = (QEQueueCtr)(qLen + 1U); /* +1 for frontEvt */
- me->nMin = me->nFree;</code>
- </operation>
- <!--${QF::QEQueue::post}-->
- <operation name="post" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! Post an event to the "raw" thread-safe event queue (FIFO).
- * @public @memberof QEQueue
- *
- * @details
- * Post an event to the "raw" thread-safe event queue using the
- * First-In-First-Out (FIFO) order.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] e pointer to the event to be posted to the queue
- * @param[in] margin number of required free slots in the queue after
- * posting the event. The special value #QF_NO_MARGIN
- * means that this function will assert if posting
- * @returns 'true' (success) when the posting succeeded with the provided
- * margin and 'false' (failure) when the posting fails.
- *
- * @precondition{qf_qeq,200}
- * - event must be valid
- *
- * @note
- * The #QF_NO_MARGIN value of the `margin` parameter is special and
- * denotes situation when the post() operation is assumed to succeed (event
- * delivery guarantee). An assertion fires, when the event cannot be
- * delivered in this case.
- *
- * @note This function can be called from any task context or ISR context.
- *
- * @sa QEQueue_postLIFO(), QEQueue_get()
- */
- /*! @public @memberof QEQueue */</documentation>
- <!--${QF::QEQueue::post::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QF::QEQueue::post::margin}-->
- <parameter name="margin" type="uint_fast16_t const"/>
- <!--${QF::QEQueue::post::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- Q_REQUIRE_ID(200, e != (QEvt *)0);
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QEQueueCtr nFree = me->nFree; /* get volatile into temporary */
- /* required margin available? */
- bool status;
- if (((margin == QF_NO_MARGIN) && (nFree > 0U))
- || (nFree > (QEQueueCtr)margin))
- {
- /* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- QEvt_refCtr_inc_(e); /* increment the reference counter */
- }
- --nFree; /* one free entry just used up */
- me->nFree = nFree; /* update the original */
- if (me->nMin > nFree) {
- me->nMin = nFree; /* update minimum so far */
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_POST, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this queue object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* number of free entries */
- QS_EQC_PRE_(me->nMin); /* min number of free entries */
- QS_END_NOCRIT_PRE_()
- /* was the queue empty? */
- if (me->frontEvt == (QEvt *)0) {
- me->frontEvt = e; /* deliver event directly */
- }
- /* queue was not empty, insert event into the ring-buffer */
- else {
- /* insert event into the ring buffer (FIFO)... */
- me->ring[me->head] = e; /* insert e into buffer */
- /* need to wrap the head? */
- if (me->head == 0U) {
- me->head = me->end; /* wrap around */
- }
- --me->head;
- }
- status = true; /* event posted successfully */
- }
- else {
- /*! @note assert if event cannot be posted and dropping events is
- * not acceptable
- */
- Q_ASSERT_CRIT_(210, margin != QF_NO_MARGIN);
- QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_POST_ATTEMPT, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this queue object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* number of free entries */
- QS_EQC_PRE_(margin); /* margin requested */
- QS_END_NOCRIT_PRE_()
- status = false;
- }
- QF_CRIT_X_();
- return status;</code>
- </operation>
- <!--${QF::QEQueue::postLIFO}-->
- <operation name="postLIFO" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Post an event to the "raw" thread-safe event queue (LIFO).
- * @public @memberof QEQueue
- *
- * @details
- * Post an event to the "raw" thread-safe event queue using the
- * Last-In-First-Out (LIFO) order.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] e pointer to the event to be posted to the queue
- *
- * @precondition{qf_qeq,300}
- * - the queue must be able to accept the event (cannot overflow)
- * @attention
- * The LIFO policy should be used only with great __caution__, because
- * it alters the order of events in the queue.
- *
- * @note
- * This function can be called from any task context or ISR context.
- *
- * @note
- * this function is used for the "raw" thread-safe queues and __not__
- * for the queues of active objects.
- *
- * @sa
- * QEQueue_post(), QEQueue_get(), QActive_defer()
- */
- /*! @public @memberof QEQueue */</documentation>
- <!--${QF::QEQueue::postLIFO::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QF::QEQueue::postLIFO::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QEQueueCtr nFree = me->nFree; /* get volatile into temporary */
- Q_REQUIRE_CRIT_(300, nFree != 0U);
- /* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- QEvt_refCtr_inc_(e); /* increment the reference counter */
- }
- --nFree; /* one free entry just used up */
- me->nFree = nFree; /* update the original */
- if (me->nMin > nFree) {
- me->nMin = nFree; /* update minimum so far */
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_POST_LIFO, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this queue object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_);/* pool Id & ref Count of event */
- QS_EQC_PRE_(nFree); /* number of free entries */
- QS_EQC_PRE_(me->nMin); /* min number of free entries */
- QS_END_NOCRIT_PRE_()
- QEvt const * const frontEvt = me->frontEvt; /* read into temp */
- me->frontEvt = e; /* deliver event directly to the front of the queue */
- /* was the queue not empty? */
- if (frontEvt != (QEvt *)0) {
- ++me->tail;
- if (me->tail == me->end) { /* need to wrap the tail? */
- me->tail = 0U; /* wrap around */
- }
- me->ring[me->tail] = frontEvt; /* save old front evt */
- }
- QF_CRIT_X_();</code>
- </operation>
- <!--${QF::QEQueue::get}-->
- <operation name="get" type="QEvt const *" visibility="0x00" properties="0x00">
- <documentation>/*! Obtain an event from the "raw" thread-safe queue.
- * @public @memberof QEQueue
- *
- * @details
- * Retrieves an event from the front of the "raw" thread-safe queue and
- * returns a pointer to this event to the caller.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @returns
- * pointer to event at the front of the queue, if the queue is
- * not empty and NULL if the queue is empty.
- *
- * @note
- * this function is used for the "raw" thread-safe queues and __not__
- * for the queues of active objects.
- *
- * @sa
- * QEQueue_post(), QEQueue_postLIFO(), QActive_recall()
- */
- /*! @public @memberof QEQueue */</documentation>
- <!--${QF::QEQueue::get::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QEvt const * const e = me->frontEvt; /* remove event from the front */
- /* was the queue not empty? */
- if (e != (QEvt *)0) {
- /* use a temporary variable to increment me->nFree */
- QEQueueCtr const nFree = me->nFree + 1U;
- me->nFree = nFree; /* update the number of free */
- /* any events in the ring buffer? */
- if (nFree <= me->end) {
- me->frontEvt = me->ring[me->tail]; /* get from tail */
- if (me->tail == 0U) { /* need to wrap the tail? */
- me->tail = me->end; /* wrap around */
- }
- --me->tail;
- QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_GET, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this queue object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_);/* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* number of free entries */
- QS_END_NOCRIT_PRE_()
- }
- else {
- me->frontEvt = (QEvt *)0; /* queue becomes empty */
- /* all entries in the queue must be free (+1 for fronEvt) */
- Q_ASSERT_CRIT_(410, nFree == (me->end + 1U));
- QS_BEGIN_NOCRIT_PRE_(QS_QF_EQUEUE_GET_LAST, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this queue object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_END_NOCRIT_PRE_()
- }
- }
- QF_CRIT_X_();
- return e;</code>
- </operation>
- <!--${QF::QEQueue::getNFree}-->
- <operation name="getNFree" type="QEQueueCtr" visibility="0x00" properties="0x02">
- <specifiers>const</specifiers>
- <documentation>/*! "raw" thread-safe QF event queue operation for obtaining the number
- * of free entries still available in the queue.
- * @public @memberof QEQueue
- *
- * @details
- * This operation needs to be used with caution because the number of free
- * entries can change unexpectedly. The main intent for using this operation
- * is in conjunction with event deferral. In this case the queue is accessed
- * only from a single thread (by a single AO), so the number of free
- * entries cannot change unexpectedly.
- *
- * @param[in] me current instance pointer (see @ref oop)
- *
- * @returns the current number of free slots in the queue.
- */
- /*! @public @memberof QEQueue */</documentation>
- <code>return me->nFree;</code>
- </operation>
- <!--${QF::QEQueue::getNMin}-->
- <operation name="getNMin" type="QEQueueCtr" visibility="0x00" properties="0x02">
- <specifiers>const</specifiers>
- <documentation>/*! "raw" thread-safe QF event queue operation for obtaining the minimum
- * number of free entries ever in the queue (a.k.a. "low-watermark").
- * @public @memberof QEQueue
- *
- * @details
- * This operation needs to be used with caution because the "low-watermark"
- * can change unexpectedly. The main intent for using this operation is to
- * get an idea of queue usage to size the queue adequately.
- *
- * @param[in] me current instance pointer (see @ref oop)
- *
- * @returns the minimum number of free entries ever in the queue since init.
- */
- /*! @public @memberof QEQueue */</documentation>
- <code>return me->nMin;</code>
- </operation>
- <!--${QF::QEQueue::isEmpty}-->
- <operation name="isEmpty" type="bool" visibility="0x00" properties="0x02">
- <specifiers>const</specifiers>
- <documentation>/*! "raw" thread-safe QF event queue operation to find out if the queue
- * is empty.
- * @public @memberof QEQueue
- *
- * @details
- * This operation needs to be used with caution because the queue status
- * can change unexpectedly. The main intent for using this operation is in
- * conjunction with event deferral. In this case the queue is accessed only
- * from a single thread (by a single AO), so no other entity can post
- * events to the queue.
- *
- * @param[in] me_ current instance pointer (see @ref oop)
- *
- * @returns 'true' if the queue is current empty and 'false' otherwise.
- */
- /*! @public @memberof QEQueue */</documentation>
- <code>return me->frontEvt == (QEvt *)0;</code>
- </operation>
- </class>
- <!--${QF::QMPool}-->
- <class name="QMPool">
- <documentation>/*! @brief Native QF Memory Pool
- * @class QMPool
- *
- * @details
- * A fixed block-size memory pool is a very fast and efficient data
- * structure for dynamic allocation of fixed block-size chunks of memory.
- * A memory pool offers fast and deterministic allocation and recycling of
- * memory blocks and is not subject to fragmenation.<br>
- *
- * The ::QMPool class describes the native QF memory pool, which can be used as
- * the event pool for dynamic event allocation, or as a fast, deterministic
- * fixed block-size heap for any other objects in your application.
- *
- * @note
- * ::QMPool contains only data members for managing a memory pool, but
- * does not contain the pool storage, which must be provided externally
- * during the pool initialization.
- *
- * @note
- * The native QF event pool is configured by defining the macro
- * #QF_EPOOL_TYPE_ as ::QMPool in the specific QF port header file.
- */</documentation>
- <!--${QF::QMPool::start}-->
- <attribute name="start" type="void *" visibility="0x02" properties="0x00">
- <documentation>/*! start of the memory managed by this memory pool
- * @private @memberof QMPool
- */</documentation>
- </attribute>
- <!--${QF::QMPool::end}-->
- <attribute name="end" type="void *" visibility="0x02" properties="0x00">
- <documentation>/*! end of the memory managed by this memory pool
- * @private @memberof QMPool
- */</documentation>
- </attribute>
- <!--${QF::QMPool::free_head}-->
- <attribute name="free_head" type="void * volatile" visibility="0x02" properties="0x00">
- <documentation>/*! head of linked list of free blocks
- * @private @memberof QMPool
- */</documentation>
- </attribute>
- <!--${QF::QMPool::blockSize}-->
- <attribute name="blockSize" type="QMPoolSize" visibility="0x02" properties="0x00">
- <documentation>/*! maximum block size (in bytes)
- * @private @memberof QMPool
- */</documentation>
- </attribute>
- <!--${QF::QMPool::nTot}-->
- <attribute name="nTot" type="QMPoolCtr" visibility="0x02" properties="0x00">
- <documentation>/*! total number of blocks
- * @private @memberof QMPool
- */</documentation>
- </attribute>
- <!--${QF::QMPool::nFree}-->
- <attribute name="nFree" type="QMPoolCtr volatile" visibility="0x02" properties="0x00">
- <documentation>/*! number of free blocks remaining
- * @private @memberof QMPool
- */</documentation>
- </attribute>
- <!--${QF::QMPool::nMin}-->
- <attribute name="nMin" type="QMPoolCtr" visibility="0x02" properties="0x00">
- <documentation>/*! minimum number of free blocks ever present in this pool
- * @private @memberof QMPool
- *
- * @details
- * this attribute remembers the low watermark of the pool, which
- * provides a valuable information for sizing event pools.
- * @sa QF_getPoolMin().
- */</documentation>
- </attribute>
- <!--${QF::QMPool::init}-->
- <operation name="init" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Initializes the native QF memory pool
- * @public @memberof QMPool
- *
- * @details
- * Initialize a fixed block-size memory pool by providing it with the pool
- * memory to manage, size of this memory, and the block size.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] poolSto pointer to the memory buffer for pool storage
- * @param[in] poolSize size of the storage buffer in bytes
- * @param[in] blockSize fixed-size of the memory blocks in bytes
- *
- * @precondition{qf_mem,100}
- * - the memory block must be valid
- * - the poolSize must fit at least one free block
- * - the blockSize must not be too close to the top of the dynamic range
- *
- * @attention
- * The caller of QMPool::init() must make sure that the `poolSto`
- * pointer is properly **aligned**. In particular, it must be possible to
- * efficiently store a pointer at the location pointed to by `poolSto`.
- * Internally, the QMPool_init() function rounds up the block size
- * `blockSize` so that it can fit an integer number of pointers.
- * This is done to achieve proper alignment of the blocks within the pool.
- *
- * @note
- * Due to the rounding of block size the actual capacity of the pool might
- * be less than (`poolSize` / `blockSize`). You can check the capacity
- * of the pool by calling the QF_getPoolMin() function.
- *
- * @note
- * This function is **not** protected by a critical section, because
- * it is intended to be called only during the initialization of the system,
- * when interrupts are not allowed yet.
- *
- * @note
- * Many QF ports use memory pools to implement the event pools.
- *
- * @usage
- * The following example illustrates how to invoke QMPool_init():
- * @include qmp_init.c
- */
- /*! @public @memberof QMPool */</documentation>
- <!--${QF::QMPool::init::poolSto}-->
- <parameter name="poolSto" type="void * const"/>
- <!--${QF::QMPool::init::poolSize}-->
- <parameter name="poolSize" type="uint_fast32_t"/>
- <!--${QF::QMPool::init::blockSize}-->
- <parameter name="blockSize" type="uint_fast16_t"/>
- <code>Q_REQUIRE_ID(100, (poolSto != (void *)0)
- && (poolSize >= (uint_fast32_t)sizeof(QFreeBlock))
- && ((uint_fast16_t)(blockSize + sizeof(QFreeBlock)) > blockSize));
- me->free_head = poolSto;
- /* round up the blockSize to fit an integer # free blocks, no division */
- me->blockSize = (QMPoolSize)sizeof(QFreeBlock); /* start with just one */
- /* #free blocks that fit in one memory block */
- uint_fast16_t nblocks = 1U;
- while (me->blockSize < (QMPoolSize)blockSize) {
- me->blockSize += (QMPoolSize)sizeof(QFreeBlock);
- ++nblocks;
- }
- blockSize = (uint_fast16_t)me->blockSize; /* round-up to nearest block */
- /* the pool buffer must fit at least one rounded-up block */
- Q_ASSERT_ID(110, poolSize >= blockSize);
- /* chain all blocks together in a free-list... */
- poolSize -= (uint_fast32_t)blockSize; /* don't count the last block */
- me->nTot = 1U; /* the last block already in the pool */
- /* start at the head of the free list */
- QFreeBlock *fb = (QFreeBlock *)me->free_head;
- /* chain all blocks together in a free-list... */
- while (poolSize >= (uint_fast32_t)blockSize) {
- fb->next = &fb[nblocks]; /* point next link to next block */
- fb = fb->next; /* advance to the next block */
- poolSize -= (uint_fast32_t)blockSize; /* reduce available pool size */
- ++me->nTot; /* increment the number of blocks so far */
- }
- fb->next = (QFreeBlock *)0; /* the last link points to NULL */
- me->nFree = me->nTot; /* all blocks are free */
- me->nMin = me->nTot; /* the minimum number of free blocks */
- me->start = poolSto; /* the original start this pool buffer */
- me->end = fb; /* the last block in this pool */</code>
- </operation>
- <!--${QF::QMPool::get}-->
- <operation name="get" type="void *" visibility="0x00" properties="0x00">
- <documentation>/*! Obtains a memory block from a memory pool.
- * @public @memberof QMPool
- *
- * @details
- * The function allocates a memory block from the pool and returns a pointer
- * to the block back to the caller.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] margin the minimum number of unused blocks still available
- * in the pool after the allocation.
- *
- * @returns
- * A pointer to a memory block or NULL if no more blocks are available in
- * the memory pool.
- *
- * @note
- * This function can be called from any task level or ISR level.
- *
- * @note
- * The memory pool `me` must be initialized before any events can
- * be requested from it. Also, the QMPool_get() function uses internally a
- * QF critical section, so you should be careful not to call it from within
- * a critical section when nesting of critical section is not supported.
- *
- * @attention
- * An allocated block must be later returned back to the **same** pool
- * from which it has been allocated.
- *
- * @sa QMPool_put()
- *
- * @trace
- * @tr{PQP18_3}
- *
- * @usage
- * The following example illustrates how to use QMPool_get():
- * @include qmp_use.c
- */
- /*! @public @memberof QMPool */</documentation>
- <!--${QF::QMPool::get::margin}-->
- <parameter name="margin" type="uint_fast16_t const"/>
- <!--${QF::QMPool::get::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- QF_CRIT_STAT_
- QF_CRIT_E_();
- /* have more free blocks than the requested margin? */
- QFreeBlock *fb;
- if (me->nFree > (QMPoolCtr)margin) {
- void *fb_next;
- fb = (QFreeBlock *)me->free_head; /* get a free block */
- /* the pool has some free blocks, so a free block must be available */
- Q_ASSERT_CRIT_(310, fb != (QFreeBlock *)0);
- fb_next = fb->next; /* put volatile into temporary */
- /* is the pool becoming empty? */
- --me->nFree; /* one less free block */
- if (me->nFree == 0U) {
- /* pool is becoming empty, so the next free block must be NULL */
- Q_ASSERT_CRIT_(320, fb_next == (QFreeBlock *)0);
- me->nMin = 0U; /* remember that the pool got empty */
- }
- else {
- /*! @invariant
- * The pool is not empty, so the next free-block pointer,
- * so the next free block must be in range.
- */
- /* NOTE: The next free block pointer can fall out of range
- * when the client code writes past the memory block, thus
- * corrupting the next block.
- */
- Q_ASSERT_CRIT_(330,
- (me->start <= fb_next) && (fb_next <= me->end));
- /* is the number of free blocks the new minimum so far? */
- if (me->nMin > me->nFree) {
- me->nMin = me->nFree; /* remember the new minimum */
- }
- }
- me->free_head = fb_next; /* set the head to the next free block */
- QS_BEGIN_NOCRIT_PRE_(QS_QF_MPOOL_GET, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this memory pool */
- QS_MPC_PRE_(me->nFree); /* # of free blocks in the pool */
- QS_MPC_PRE_(me->nMin); /* min # free blocks ever in the pool */
- QS_END_NOCRIT_PRE_()
- }
- /* don't have enough free blocks at this point */
- else {
- fb = (QFreeBlock *)0;
- QS_BEGIN_NOCRIT_PRE_(QS_QF_MPOOL_GET_ATTEMPT, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this memory pool */
- QS_MPC_PRE_(me->nFree); /* # of free blocks in the pool */
- QS_MPC_PRE_(margin); /* the requested margin */
- QS_END_NOCRIT_PRE_()
- }
- QF_CRIT_X_();
- return fb; /* return the block or NULL pointer to the caller */</code>
- </operation>
- <!--${QF::QMPool::put}-->
- <operation name="put" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Recycles a memory block back to a memory pool.
- * @public @memberof QMPool
- *
- * @details
- * Recycle a memory block to the fixed block-size memory pool.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] b pointer to the memory block that is being recycled
- *
- * @precondition{qf_mem,200}
- * - the number of free blocks cannot exceed the total # blocks
- * - the block pointer must be in range for this pool.
- *
- * @attention
- * The recycled block must be allocated from the **same** memory pool
- * to which it is returned.
- *
- * @note
- * This function can be called from any task level or ISR level.
- *
- * @sa
- * QMPool_get()
- *
- * @usage
- * The following example illustrates how to use QMPool_put():
- * @include qmp_use.c
- */
- /*! @public @memberof QMPool */</documentation>
- <!--${QF::QMPool::put::b}-->
- <parameter name="b" type="void * const"/>
- <!--${QF::QMPool::put::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(qs_id);
- #endif
- Q_REQUIRE_ID(200, (me->nFree < me->nTot)
- && (me->start <= b) && (b <= me->end));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- ((QFreeBlock *)b)->next = (QFreeBlock *)me->free_head;/* link into list */
- me->free_head = b; /* set as new head of the free list */
- ++me->nFree; /* one more free block in this pool */
- QS_BEGIN_NOCRIT_PRE_(QS_QF_MPOOL_PUT, qs_id)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this memory pool */
- QS_MPC_PRE_(me->nFree); /* the number of free blocks in the pool */
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_();</code>
- </operation>
- </class>
- <!--${QF::QF-base}-->
- <package name="QF-base" stereotype="0x02" namespace="QF_">
- <!--${QF::QF-base::Attr}-->
- <attribute name="Attr" type="typedef struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief QF active object framework
- * @class QF
- */</documentation>
- <code>{
- uint8_t dummy; /*< dummy attribute */
- } QF;</code>
- </attribute>
- <!--${QF::QF-base::intLock_}-->
- <attribute name="intLock_" type="uint_fast8_t volatile" visibility="0x00" properties="0x01">
- <documentation>/*! Interrupt lock up-down counter (used in some QF ports )
- * @static @private @memberof QF
- */</documentation>
- </attribute>
- <!--${QF::QF-base::intNest_}-->
- <attribute name="intNest_" type="uint_fast8_t volatile" visibility="0x00" properties="0x01">
- <documentation>/*! Interrupt nesting up-down counter (used in some QF ports )
- * @static @private @memberof QF
- */</documentation>
- </attribute>
- <!--${QF::QF-base::init}-->
- <operation name="init" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QF initialization
- * @static @public @memberof QF
- *
- * @details
- * Initializes QF and must be called exactly once before any other QF
- * function. Typcially, QF_init() is called from main() even before
- * initializing the Board Support Package (BSP).
- *
- * @note
- * QF_init() clears the internal QF variables, so that the framework
- * can start correctly even if the startup code fails to clear the
- * uninitialized data (as is required by the C Standard).
- */
- /*! @static @public @memberof QF */</documentation>
- </operation>
- <!--${QF::QF-base::stop}-->
- <operation name="stop" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Function invoked by the application layer to stop the QF
- * application and return control to the OS/Kernel.
- * @static @public @memberof QF
- *
- * @details
- * This function stops the QF application. After calling this function,
- * QF attempts to gracefully stop the application. This graceful shutdown
- * might take some time to complete. The typical use of this function is
- * for terminating the QF application to return back to the operating
- * system or for handling fatal errors that require shutting down
- * (and possibly re-setting) the system.
- *
- * @attention
- * After calling QF_stop() the application must terminate and cannot
- * continue. In particular, QF_stop() is **not** intended to be followed
- * by a call to QF_init() to "resurrect" the application.
- *
- * @sa QF_onCleanup()
- */
- /*! @static @public @memberof QF */</documentation>
- </operation>
- <!--${QF::QF-base::run}-->
- <operation name="run" type="int_t" visibility="0x00" properties="0x01">
- <documentation>/*! Transfers control to QF to run the application.
- * @static @public @memberof QF
- *
- * @details
- * QF_run() is typically called from your startup code after you initialize
- * the QF and start at least one active object with QACTIVE_START().
- *
- * @returns
- * In QK, the QF_run() does not return.
- */
- /*! @static @public @memberof QF */</documentation>
- </operation>
- <!--${QF::QF-base::psInit}-->
- <operation name="psInit" type="void" visibility="0x00" properties="0x03">
- <documentation>/*! initialization of publish-subscribe
- *
- * @deprecated
- * @sa QActive_psInit()
- */</documentation>
- <!--${QF::QF-base::psInit::subscrSto}-->
- <parameter name="subscrSto" type="QSubscrList * const"/>
- <!--${QF::QF-base::psInit::maxSignal}-->
- <parameter name="maxSignal" type="enum_t const"/>
- <code>QActive_psInit(subscrSto, maxSignal);</code>
- </operation>
- <!--${QF::QF-base::getQueueMin}-->
- <operation name="getQueueMin" type="uint_fast16_t" visibility="0x00" properties="0x01">
- <documentation>/*! This function returns the minimum of free entries of
- * the given event queue.
- * @static @public @memberof QF
- *
- * @details
- * Queries the minimum of free ever present in the given event queue of
- * an active object with priority `prio`, since the active object
- * was started.
- *
- * @note
- * This function is available only when the native QF event queue
- * implementation is used. Requesting the queue minimum of an unused
- * priority level raises an assertion in the QF. (A priority level becomes
- * used in QF after the call to the QActive_register_() function.)
- *
- * @param[in] prio Priority of the active object, whose queue is queried
- *
- * @returns
- * the minimum of free ever present in the given event queue of an active
- * object with priority `prio`, since the active object was started.
- */
- /*! @static @public @memberof QF */</documentation>
- <!--${QF::QF-base::getQueueMin::prio}-->
- <parameter name="prio" type="uint_fast8_t const"/>
- <code>Q_REQUIRE_ID(400, (prio <= QF_MAX_ACTIVE)
- && (QActive_registry_[prio] != (QActive *)0));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- uint_fast16_t const min =
- (uint_fast16_t)QActive_registry_[prio]->eQueue.nMin;
- QF_CRIT_X_();
- return min;</code>
- </operation>
- <!--${QF::QF-base::onStartup}-->
- <operation name="onStartup" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Startup QF callback.
- * @static @public @memberof QF
- *
- * @details
- * The purpose of the QF_onStartup() callback is to configure and enable
- * hardware interrupts. The callback is invoked from QF_run(), right before
- * starting the underlying real-time kernel. By that time, the application
- * is considered ready to receive and service interrupts.
- *
- * This function is application-specific and is not implemented in QF, but
- * rather in the Board Support Package (BSP) for the given application.
- */
- /*! @static @public @memberof QF */</documentation>
- </operation>
- <!--${QF::QF-base::onCleanup}-->
- <operation name="onCleanup" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Cleanup QF callback.
- * @static @public @memberof QF
- *
- * @details
- * QF_onCleanup() is called in some QF ports before QF returns to the
- * underlying real-time kernel or operating system.
- *
- * This function is strongly platform-specific and is not implemented in
- * the QF, but either in the QF port or in the Board Support Package (BSP)
- * for the given application. Some QF ports might not require implementing
- * QF_onCleanup() at all, because many embedded applications don't have
- * anything to exit to.
- *
- * @sa QF_stop()
- */
- /*! @static @public @memberof QF */</documentation>
- </operation>
- </package>
- <!--${QF::QF-dyn}-->
- <package name="QF-dyn" stereotype="0x02" namespace="QF_">
- <!--${QF::QF-dyn::poolInit}-->
- <operation name="poolInit" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Event pool initialization for dynamic allocation of events.
- * @static @public @memberof QF
- *
- * @details
- * This function initializes one event pool at a time and must be called
- * exactly once for each event pool before the pool can be used.
- *
- * @param[in] poolSto pointer to the storage for the event pool
- * @param[in] poolSize size of the storage for the pool in bytes
- * @param[in] evtSize the block-size of the pool in bytes, which determines
- * the maximum size of events that can be allocated from the pool.
- *
- * @attention
- * You might initialize many event pools by making many consecutive calls
- * to the QF_poolInit() function. However, for the simplicity of the internal
- * implementation, you must initialize event pools in the **ascending order**
- * of the event size.
- *
- * Many RTOSes provide fixed block-size heaps, a.k.a. memory pools that can
- * be adapted for QF event pools. In case such support is missing, QF provides
- * a native QF event pool implementation. The macro #QF_EPOOL_TYPE_ determines
- * the type of event pool used by a particular QF port. See structure ::QMPool
- * for more information.
- *
- * @note The actual number of events available in the pool might be actually
- * less than (`poolSize` / `evtSize`) due to the internal alignment
- * of the blocks that the pool might perform. You can always check the
- * capacity of the pool by calling QF_getPoolMin().
- *
- * @note The dynamic allocation of events is optional, meaning that you
- * might choose not to use dynamic events. In that case calling QF_poolInit()
- * and using up memory for the memory blocks is unnecessary.
- *
- * @sa QF initialization example for QF_init()
- */
- /*! @static @public @memberof QF */</documentation>
- <!--${QF::QF-dyn::poolInit::poolSto}-->
- <parameter name="poolSto" type="void * const"/>
- <!--${QF::QF-dyn::poolInit::poolSize}-->
- <parameter name="poolSize" type="uint_fast32_t const"/>
- <!--${QF::QF-dyn::poolInit::evtSize}-->
- <parameter name="evtSize" type="uint_fast16_t const"/>
- <code>/*! @pre cannot exceed the number of available memory pools */
- Q_REQUIRE_ID(200, QF_maxPool_ < QF_MAX_EPOOL);
- /*! @pre please initialize event pools in ascending order of evtSize: */
- Q_REQUIRE_ID(201, (QF_maxPool_ == 0U)
- || (QF_EPOOL_EVENT_SIZE_(QF_ePool_[QF_maxPool_ - 1U])
- < evtSize));
- /* perform the platform-dependent initialization of the pool */
- QF_EPOOL_INIT_(QF_ePool_[QF_maxPool_], poolSto, poolSize, evtSize);
- ++QF_maxPool_; /* one more pool */
- #ifdef Q_SPY
- /* generate the object-dictionary entry for the initialized pool */
- {
- uint8_t obj_name[9] = "EvtPool?";
- obj_name[7] = (uint8_t)(((uint8_t)'0' + QF_maxPool_) & 0x7FU);
- QS_obj_dict_pre_(&QF_ePool_[QF_maxPool_ - 1U], (char const *)obj_name);
- }
- #endif /* Q_SPY*/</code>
- </operation>
- <!--${QF::QF-dyn::poolGetMaxBlockSize}-->
- <operation name="poolGetMaxBlockSize" type="uint_fast16_t" visibility="0x00" properties="0x01">
- <documentation>/*! Obtain the block size of any registered event pools.
- * @static @public @memberof QF
- *
- * @details
- * Obtain the block size of any registered event pools
- */
- /*! @static @public @memberof QF */</documentation>
- <code>return QF_EPOOL_EVENT_SIZE_(QF_ePool_[QF_maxPool_ - 1U]);</code>
- </operation>
- <!--${QF::QF-dyn::getPoolMin}-->
- <operation name="getPoolMin" type="uint_fast16_t" visibility="0x00" properties="0x01">
- <documentation>/*! Obtain the minimum of free entries of the given event pool.
- * @static @public @memberof QF
- *
- * @details
- * This function obtains the minimum number of free blocks in the given
- * event pool since this pool has been initialized by a call to QF_poolInit().
- *
- * @param[in] poolId event pool ID in the range 1..QF_maxPool_, where
- * QF_maxPool_ is the number of event pools initialized
- * with the function QF_poolInit().
- *
- * @returns
- * the minimum number of unused blocks in the given event pool.
- */
- /*! @static @public @memberof QF */</documentation>
- <!--${QF::QF-dyn::getPoolMin::poolId}-->
- <parameter name="poolId" type="uint_fast8_t const"/>
- <code>/*! @pre the poolId must be in range */
- Q_REQUIRE_ID(400, (poolId <= QF_MAX_EPOOL)
- && (0U < poolId) && (poolId <= QF_maxPool_));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- uint_fast16_t const min = (uint_fast16_t)QF_ePool_[poolId - 1U].nMin;
- QF_CRIT_X_();
- return min;</code>
- </operation>
- <!--${QF::QF-dyn::newX_}-->
- <operation name="newX_" type="QEvt *" visibility="0x00" properties="0x01">
- <documentation>/*! Internal QF implementation of creating new dynamic event.
- * @static @private @memberof QF
- *
- * @details
- * Allocates an event dynamically from one of the QF event pools.
- *
- * @param[in] evtSize the size (in bytes) of the event to allocate
- * @param[in] margin the number of un-allocated events still available
- * in a given event pool after the allocation completes.
- * The special value ::QF_NO_MARGIN means that this function
- * will assert if allocation fails.
- * @param[in] sig the signal to be assigned to the allocated event
- *
- * @returns
- * pointer to the newly allocated event. This pointer can be NULL only if
- * margin != #QF_NO_MARGIN and the event cannot be allocated with the
- * specified margin still available in the given pool.
- *
- * @note
- * The internal QF function QF_newX_() raises an assertion when the
- * `margin` parameter is #QF_NO_MARGIN and allocation of the event turns
- * out to be impossible due to event pool depletion, or incorrect (too big)
- * size of the requested event.
- *
- * @note
- * The application code should not call this function directly.
- * The only allowed use is thorough the macros Q_NEW() or Q_NEW_X().
- */
- /*! @static @private @memberof QF */</documentation>
- <!--${QF::QF-dyn::newX_::evtSize}-->
- <parameter name="evtSize" type="uint_fast16_t const"/>
- <!--${QF::QF-dyn::newX_::margin}-->
- <parameter name="margin" type="uint_fast16_t const"/>
- <!--${QF::QF-dyn::newX_::sig}-->
- <parameter name="sig" type="enum_t const"/>
- <code>uint_fast8_t idx;
- /* find the pool index that fits the requested event size ... */
- for (idx = 0U; idx < QF_maxPool_; ++idx) {
- if (evtSize <= QF_EPOOL_EVENT_SIZE_(QF_ePool_[idx])) {
- break;
- }
- }
- /* cannot run out of registered pools */
- Q_ASSERT_ID(310, idx < QF_maxPool_);
- /* get e -- platform-dependent */
- QEvt *e;
- #ifdef Q_SPY
- QF_EPOOL_GET_(QF_ePool_[idx], e,
- ((margin != QF_NO_MARGIN) ? margin : 0U),
- (uint_fast8_t)QS_EP_ID + idx + 1U);
- #else
- QF_EPOOL_GET_(QF_ePool_[idx], e,
- ((margin != QF_NO_MARGIN) ? margin : 0U), 0U);
- #endif
- /* was e allocated correctly? */
- QS_CRIT_STAT_
- if (e != (QEvt *)0) {
- e->sig = (QSignal)sig; /* set signal for this event */
- e->poolId_ = (uint8_t)(idx + 1U); /* store the pool ID */
- e->refCtr_ = 0U; /* set the reference counter to 0 */
- QS_BEGIN_PRE_(QS_QF_NEW, (uint_fast8_t)QS_EP_ID + e->poolId_)
- QS_TIME_PRE_(); /* timestamp */
- QS_EVS_PRE_(evtSize); /* the size of the event */
- QS_SIG_PRE_(sig); /* the signal of the event */
- QS_END_PRE_()
- }
- /* event cannot be allocated */
- else {
- /* This assertion means that the event allocation failed,
- * and this failure cannot be tolerated. The most frequent
- * reason is an event leak in the application.
- */
- Q_ASSERT_ID(320, margin != QF_NO_MARGIN);
- QS_BEGIN_PRE_(QS_QF_NEW_ATTEMPT, (uint_fast8_t)QS_EP_ID + idx + 1U)
- QS_TIME_PRE_(); /* timestamp */
- QS_EVS_PRE_(evtSize); /* the size of the event */
- QS_SIG_PRE_(sig); /* the signal of the event */
- QS_END_PRE_()
- }
- return e; /* can't be NULL if we can't tolerate failed allocation */</code>
- </operation>
- <!--${QF::QF-dyn::gc}-->
- <operation name="gc" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Recycle a dynamic event
- * @static @public @memberof QF
- *
- * @details
- * This function implements a simple garbage collector for the dynamic events.
- * Only dynamic events are candidates for recycling. (A dynamic event is one
- * that is allocated from an event pool, which is determined as non-zero
- * e->poolId_ attribute.) Next, the function decrements the reference counter
- * of the event (e->refCtr_), and recycles the event only if the counter drops
- * to zero (meaning that no more references are outstanding for this event).
- * The dynamic event is recycled by returning it to the pool from which
- * it was originally allocated.
- *
- * @param[in] e pointer to the event to recycle
- *
- * @note
- * QF invokes the garbage collector at all appropriate contexts, when
- * an event can become garbage (automatic garbage collection), so the
- * application code should have no need to call QF_gc() directly. The QF_gc()
- * function is exposed only for special cases when your application sends
- * dynamic events to the "raw" thread-safe queues (see ::QEQueue). Such
- * queues are processed outside of QF and the automatic garbage collection
- * is **NOT** performed for these events. In this case you need to call
- * QF_gc() explicitly.
- */
- /*! @static @public @memberof QF */</documentation>
- <!--${QF::QF-dyn::gc::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <code>/* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- QF_CRIT_STAT_
- QF_CRIT_E_();
- /* isn't this the last reference? */
- if (e->refCtr_ > 1U) {
- QS_BEGIN_NOCRIT_PRE_(QS_QF_GC_ATTEMPT,
- (uint_fast8_t)QS_EP_ID + e->poolId_)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_END_NOCRIT_PRE_()
- QEvt_refCtr_dec_(e); /* decrement the ref counter */
- QF_CRIT_X_();
- }
- /* this is the last reference to this event, recycle it */
- else {
- uint_fast8_t const idx = (uint_fast8_t)e->poolId_ - 1U;
- QS_BEGIN_NOCRIT_PRE_(QS_QF_GC,
- (uint_fast8_t)QS_EP_ID + e->poolId_)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_();
- /* pool ID must be in range */
- Q_ASSERT_ID(410, idx < QF_maxPool_);
- /* cast 'const' away, which is OK, because it's a pool event */
- #ifdef Q_SPY
- QF_EPOOL_PUT_(QF_ePool_[idx], (QEvt *)e,
- (uint_fast8_t)QS_EP_ID + e->poolId_);
- #else
- QF_EPOOL_PUT_(QF_ePool_[idx], (QEvt *)e, 0U);
- #endif
- }
- }</code>
- </operation>
- <!--${QF::QF-dyn::newRef_}-->
- <operation name="newRef_" type="QEvt const *" visibility="0x00" properties="0x01">
- <documentation>/*! Internal QF implementation of creating new event reference.
- * @static @private @memberof QF
- *
- * @details
- * Creates and returns a new reference to the current event e
- *
- * @param[in] e pointer to the current event
- * @param[in] evtRef the event reference
- *
- * @returns
- * the newly created reference to the event `e`
- *
- * @note
- * The application code should not call this function directly.
- * The only allowed use is thorough the macro Q_NEW_REF().
- */
- /*! @static @private @memberof QF */</documentation>
- <!--${QF::QF-dyn::newRef_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QF::QF-dyn::newRef_::evtRef}-->
- <parameter name="evtRef" type="void const * const"/>
- <code>#ifdef Q_NASSERT
- Q_UNUSED_PAR(evtRef);
- #endif
- /*! @pre the event must be dynamic and the provided event reference
- * must not be already in use */
- Q_REQUIRE_ID(500,
- (e->poolId_ != 0U)
- && (evtRef == (void *)0));
- QF_CRIT_STAT_
- QF_CRIT_E_();
- QEvt_refCtr_inc_(e); /* increments the ref counter */
- QS_BEGIN_NOCRIT_PRE_(QS_QF_NEW_REF,
- (uint_fast8_t)QS_EP_ID + e->poolId_)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_();
- return e;</code>
- </operation>
- <!--${QF::QF-dyn::deleteRef_}-->
- <operation name="deleteRef_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Internal QF implementation of deleting event reference.
- * @static @private @memberof QF
- *
- * @details
- * Deletes an existing reference to the event e
- *
- * @param[in] evtRef the event reference
- *
- * @note
- * The application code should not call this function directly.
- * The only allowed use is thorough the macro Q_DELETE_REF().
- */
- /*! @static @private @memberof QF */</documentation>
- <!--${QF::QF-dyn::deleteRef_::evtRef}-->
- <parameter name="evtRef" type="void const * const"/>
- <code>QS_CRIT_STAT_
- QEvt const * const e = (QEvt const *)evtRef;
- QS_BEGIN_PRE_(QS_QF_DELETE_REF,
- (uint_fast8_t)QS_EP_ID + e->poolId_)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_END_PRE_()
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e);
- #endif</code>
- </operation>
- </package>
- <!--${QF::QF-pkg}-->
- <package name="QF-pkg" stereotype="0x02" namespace="QF_">
- <!--${QF::QF-pkg::ePool_[QF_MAX_EPOOL]}-->
- <attribute name="ePool_[QF_MAX_EPOOL]? (QF_MAX_EPOOL > 0U)" type="QF_EPOOL_TYPE_" visibility="0x00" properties="0x00">
- <documentation>/*! array of event pools managed by QF */</documentation>
- </attribute>
- <!--${QF::QF-pkg::maxPool_}-->
- <attribute name="maxPool_" type="uint_fast8_t" visibility="0x00" properties="0x00">
- <documentation>/*! number of initialized event pools */</documentation>
- </attribute>
- <!--${QF::QF-pkg::readySet_}-->
- <attribute name="readySet_" type="QPSet" visibility="0x00" properties="0x01">
- <documentation>/*! "Ready-set" of all threads used in the built-in kernels
- * @static @private @memberof QF
- */</documentation>
- </attribute>
- <!--${QF::QF-pkg::bzero}-->
- <operation name="bzero" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Clear a specified region of memory to zero.
- * @static @public @memberof QF
- *
- * @details
- * Clears a memory buffer by writing zeros byte-by-byte.
- *
- * @param[in] start pointer to the beginning of a memory buffer.
- * @param[in] len length of the memory buffer to clear (in bytes)
- *
- * @note The main application of this function is clearing the internal QF
- * variables upon startup. This is done to avoid problems with non-standard
- * startup code provided with some compilers and toolsets (e.g., TI DSPs or
- * Microchip MPLAB), which does not zero the uninitialized variables, as
- * required by the ANSI C standard.
- */
- /*! @static @public @memberof QF */</documentation>
- <!--${QF::QF-pkg::bzero::start}-->
- <parameter name="start" type="void * const"/>
- <!--${QF::QF-pkg::bzero::len}-->
- <parameter name="len" type="uint_fast16_t const"/>
- <code>uint8_t *ptr = (uint8_t *)start;
- for (uint_fast16_t n = len; n > 0U; --n) {
- *ptr = 0U;
- ++ptr;
- }</code>
- </operation>
- </package>
- <!--${QF::QF-extern-C}-->
- <package name="QF-extern-C" stereotype="0x02" namespace="QF_">
- <!--${QF::QF-extern-C::onContextSw}-->
- <operation name="onContextSw?def QF_ON_CONTEXT_SW" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! QF context switch callback used in built-in kernels (QV, QK, QXK)
- * @static @public @memberof QF
- *
- * @details
- * This callback function provides a mechanism to perform additional
- * custom operations when one of the built-in kernels switches context
- * from one thread to another.
- *
- * @param[in] prev pointer to the previous thread (active object)
- * (prev==0 means that `prev` was the idle loop)
- * @param[in] next pointer to the next thread (active object)
- * (next==0) means that `next` is the idle loop)
- * @attention
- * QF_onContextSw() is invoked with interrupts **disabled** and must also
- * return with interrupts **disabled**.
- *
- * @note
- * This callback is enabled by defining the macro #QF_ON_CONTEXT_SW.
- *
- * @include qf_oncontextsw.c
- */
- /*! @static @public @memberof QF */</documentation>
- <!--${QF::QF-extern-C::onContextSw::prev}-->
- <parameter name="prev" type="QActive *"/>
- <!--${QF::QF-extern-C::onContextSw::next}-->
- <parameter name="next" type="QActive *"/>
- </operation>
- </package>
- </package>
- <!--${QF-QMPool-impl}-->
- <package name="QF-QMPool-impl" stereotype="0x02">
- <!--${QF-QMPool-impl::QF_EPOOL_TYPE_}-->
- <attribute name="QF_EPOOL_TYPE_" type="" visibility="0x03" properties="0x00">
- <documentation>Native QF event pool</documentation>
- <code>QMPool</code>
- </attribute>
- <!--${QF-QMPool-impl::QF_EPOOL_INIT_}-->
- <operation name="QF_EPOOL_INIT_" type="" visibility="0x03" properties="0x00">
- <documentation>Native QF event pool initialization</documentation>
- <!--${QF-QMPool-impl::QF_EPOOL_INIT_::p_}-->
- <parameter name="p_" type="QMPool *"/>
- <!--${QF-QMPool-impl::QF_EPOOL_INIT_::poolSto_}-->
- <parameter name="poolSto_" type="void *"/>
- <!--${QF-QMPool-impl::QF_EPOOL_INIT_::poolSize_}-->
- <parameter name="poolSize_" type="uint_fast32_t"/>
- <!--${QF-QMPool-impl::QF_EPOOL_INIT_::evtSize_}-->
- <parameter name="evtSize_" type="uint_fast16_t"/>
- <code>\
- (QMPool_init(&(p_), (poolSto_), (poolSize_), (evtSize_)))</code>
- </operation>
- <!--${QF-QMPool-impl::QF_EPOOL_EVENT_SIZE_}-->
- <operation name="QF_EPOOL_EVENT_SIZE_" type="" visibility="0x03" properties="0x00">
- <documentation>Native QF event pool event-size getter</documentation>
- <!--${QF-QMPool-impl::QF_EPOOL_EVENT_S~::p_}-->
- <parameter name="p_" type="QMPool const *"/>
- <code>((uint_fast16_t)(p_).blockSize)</code>
- </operation>
- <!--${QF-QMPool-impl::QF_EPOOL_GET_}-->
- <operation name="QF_EPOOL_GET_" type="" visibility="0x03" properties="0x00">
- <documentation>Native QF event pool get-event</documentation>
- <!--${QF-QMPool-impl::QF_EPOOL_GET_::p_}-->
- <parameter name="p_" type="QMPool *"/>
- <!--${QF-QMPool-impl::QF_EPOOL_GET_::e_}-->
- <parameter name="e_" type="QEvt *"/>
- <!--${QF-QMPool-impl::QF_EPOOL_GET_::m_}-->
- <parameter name="m_" type="uint_fast16_t"/>
- <!--${QF-QMPool-impl::QF_EPOOL_GET_::qs_id_}-->
- <parameter name="qs_id_" type="uint8_t"/>
- <code>\
- ((e_) = (QEvt *)QMPool_get(&(p_), (m_), (qs_id_)))</code>
- </operation>
- <!--${QF-QMPool-impl::QF_EPOOL_PUT_}-->
- <operation name="QF_EPOOL_PUT_" type="" visibility="0x03" properties="0x00">
- <documentation>Native QF event pool put-event</documentation>
- <!--${QF-QMPool-impl::QF_EPOOL_PUT_::p_}-->
- <parameter name="p_" type="QMPool *"/>
- <!--${QF-QMPool-impl::QF_EPOOL_PUT_::e_}-->
- <parameter name="e_" type="QEvt *"/>
- <!--${QF-QMPool-impl::QF_EPOOL_PUT_::qs_id_}-->
- <parameter name="qs_id_" type="uint8_t"/>
- <code>\
- (QMPool_put(&(p_), (e_), (qs_id_)))</code>
- </operation>
- </package>
- <!--${QV}-->
- <package name="QV" stereotype="0x05">
- <!--${QV::QV-base}-->
- <package name="QV-base" stereotype="0x02" namespace="QV_">
- <!--${QV::QV-base::Attr}-->
- <attribute name="Attr" type="typedef struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief QV cooperative kernel
- * @class QV
- */</documentation>
- <code>{
- uint8_t dummy; /*< dummy attribute */
- } QV;</code>
- </attribute>
- <!--${QV::QV-base::onIdle}-->
- <operation name="onIdle" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QV idle callback (customized in BSPs)
- * @static @public @memberof QV
- *
- * @details
- * QV_onIdle() is called by the cooperative QV kernel (from QF_run()) when
- * the scheduler detects that no events are available for active objects
- * (the idle condition). This callback gives the application an opportunity
- * to enter a power-saving CPU mode, or perform some other idle processing
- * (such as QS software tracing output).
- *
- * @attention
- * QV_onIdle() is invoked with interrupts **DISABLED** because the idle
- * condition can be asynchronously changed at any time by an interrupt.
- * QV_onIdle() MUST enable the interrupts internally, but not before
- * putting the CPU into the low-power mode. (Ideally, enabling interrupts and
- * low-power mode should happen atomically). At the very least, the function
- * MUST enable interrupts, otherwise interrupts will remain disabled
- * permanently.
- */
- /*! @static @public @memberof QV */</documentation>
- </operation>
- </package>
- <!--${QV::QF-cust}-->
- <package name="QF-cust" stereotype="0x02" namespace="QF_">
- <!--${QV::QF-cust::init}-->
- <operation name="init" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QF initialization for QV
- * @static @public @memberof QF
- */
- /*! @static @public @memberof QF */</documentation>
- <code>#if (QF_MAX_EPOOL > 0U)
- QF_maxPool_ = 0U;
- #endif
- QF_bzero(&QTimeEvt_timeEvtHead_[0], sizeof(QTimeEvt_timeEvtHead_));
- QF_bzero(&QActive_registry_[0], sizeof(QActive_registry_));
- QF_bzero(&QF_readySet_, sizeof(QF_readySet_));
- #ifdef QV_INIT
- QV_INIT(); /* port-specific initialization of the QV kernel */
- #endif</code>
- </operation>
- <!--${QV::QF-cust::stop}-->
- <operation name="stop" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Stop the QF customization for QV
- * @static @public @memberof QF
- */
- /*! @static @public @memberof QF */</documentation>
- <code>QF_onCleanup(); /* application-specific cleanup callback */
- /* nothing else to do for the cooperative QV kernel */</code>
- </operation>
- <!--${QV::QF-cust::run}-->
- <operation name="run" type="int_t" visibility="0x00" properties="0x01">
- <documentation>/*! QF_run() customization for QV kernel
- * @static @public @memberof QF
- */
- /*! @static @public @memberof QF */</documentation>
- <code>#ifdef Q_SPY
- /* produce the QS_QF_RUN trace record */
- QF_INT_DISABLE();
- QS_beginRec_((uint_fast8_t)QS_QF_RUN);
- QS_endRec_();
- QF_INT_ENABLE();
- #endif /* Q_SPY */
- QF_onStartup(); /* application-specific startup callback */
- QF_INT_DISABLE();
- #ifdef QV_START
- QV_START(); /* port-specific startup of the QV kernel */
- #endif
- #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
- uint8_t pprev = 0U; /* previously used priority */
- #endif /* (defined QF_ON_CONTEXT_SW) || (defined Q_SPY) */
- for (;;) { /* QV event loop... */
- /* find the maximum priority AO ready to run */
- if (QPSet_notEmpty(&QF_readySet_)) {
- uint8_t const p = (uint8_t)QPSet_findMax(&QF_readySet_);
- QActive * const a = QActive_registry_[p];
- #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_NEXT, p)
- QS_TIME_PRE_(); /* timestamp */
- QS_2U8_PRE_(p, /* priority of the scheduled AO */
- pprev); /* previous priority */
- QS_END_NOCRIT_PRE_()
- #ifdef QF_ON_CONTEXT_SW
- QF_onContextSw(((pprev != 0U)
- ? QActive_registry_[pprev]
- : (QActive *)0), a);
- #endif /* QF_ON_CONTEXT_SW */
- pprev = p; /* update previous priority */
- #endif /* (defined QF_ON_CONTEXT_SW) || (defined Q_SPY) */
- QF_INT_ENABLE();
- /* perform the run-to-completion (RTC) step...
- * 1. retrieve the event from the AO's event queue, which
- * by this time must be non-empty (and QV asserts it).
- * 2. dispatch the event to the AO's state machine.
- * 3. determine if event is garbage and collect it if so
- */
- QEvt const * const e = QActive_get_(a);
- QHSM_DISPATCH(&a->super, e, a->prio);
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e);
- #endif
- QF_INT_DISABLE();
- if (a->eQueue.frontEvt == (QEvt *)0) { /* empty queue? */
- QPSet_remove(&QF_readySet_, p);
- }
- }
- else { /* no AO ready to run --> idle */
- #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
- if (pprev != 0U) {
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_IDLE, pprev)
- QS_TIME_PRE_(); /* timestamp */
- QS_U8_PRE_(pprev); /* previous priority */
- QS_END_NOCRIT_PRE_()
- #ifdef QF_ON_CONTEXT_SW
- QF_onContextSw(QActive_registry_[pprev], (QActive *)0);
- #endif /* QF_ON_CONTEXT_SW */
- pprev = 0U; /* update previous priority */
- }
- #endif /* (defined QF_ON_CONTEXT_SW) || (defined Q_SPY) */
- /* QV_onIdle() must be called with interrupts DISABLED
- * because the determination of the idle condition (all event
- * queues empty) can change at any time by an interrupt posting
- * events to a queue.
- *
- * NOTE: QV_onIdle() MUST enable interrupts internally,
- * ideally at the same time as putting the CPU into a power-
- * saving mode.
- */
- QV_onIdle();
- QF_INT_DISABLE(); /* disable interrupts before looping back */
- }
- }
- #ifdef __GNUC__ /* GNU compiler? */
- return 0;
- #endif</code>
- </operation>
- </package>
- <!--${QV::QActive}-->
- <class name="QActive">
- <documentation>/*! QActive active object class customization for QV */</documentation>
- <!--${QV::QActive::start_}-->
- <operation name="start_" type="void" visibility="0x00" properties="0x04">
- <documentation>/*! Starts execution of an active object and registers the object
- * with the framework customized for the QV kernel
- * @public @memberof QActive
- *
- * @precondition{qv,300}
- * - stack storage must not be provided because the QV kernel
- * does not need per-AO stacks.
- */
- /*! @public @memberof QActive */</documentation>
- <!--${QV::QActive::start_::prioSpec}-->
- <parameter name="prioSpec" type="QPrioSpec const"/>
- <!--${QV::QActive::start_::qSto}-->
- <parameter name="qSto" type="QEvt const * * const"/>
- <!--${QV::QActive::start_::qLen}-->
- <parameter name="qLen" type="uint_fast16_t const"/>
- <!--${QV::QActive::start_::stkSto}-->
- <parameter name="stkSto" type="void * const"/>
- <!--${QV::QActive::start_::stkSize}-->
- <parameter name="stkSize" type="uint_fast16_t const"/>
- <!--${QV::QActive::start_::par}-->
- <parameter name="par" type="void const * const"/>
- <code>Q_UNUSED_PAR(stkSto); /* not needed in QV */
- Q_UNUSED_PAR(stkSize); /* not needed in QV */
- Q_REQUIRE_ID(300, stkSto == (void *)0);
- me->prio = (uint8_t)(prioSpec & 0xFFU); /* QF-priority of the AO */
- me->pthre = (uint8_t)(prioSpec >> 8U); /* preemption-threshold */
- QActive_register_(me); /* make QF aware of this active object */
- QEQueue_init(&me->eQueue, qSto, qLen); /* init the built-in queue */
- QHSM_INIT(&me->super, par, me->prio); /* top-most initial tran. */
- QS_FLUSH(); /* flush the trace buffer to the host */</code>
- </operation>
- </class>
- </package>
- <!--${QV-impl}-->
- <package name="QV-impl" stereotype="0x02">
- <!--${QV-impl::QF_SCHED_STAT_}-->
- <attribute name="QF_SCHED_STAT_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QV scheduler lock status (not needed in QV) */</documentation>
- </attribute>
- <!--${QV-impl::QF_SCHED_LOCK_}-->
- <operation name="QF_SCHED_LOCK_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QV scheduler locking (not needed in QV) */</documentation>
- <!--${QV-impl::QF_SCHED_LOCK_::dummy}-->
- <parameter name="dummy" type=""/>
- <code>((void)0)</code>
- </operation>
- <!--${QV-impl::QF_SCHED_UNLOCK_}-->
- <operation name="QF_SCHED_UNLOCK_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QV scheduler unlocking (not needed in QV) */</documentation>
- <code>((void)0)</code>
- </operation>
- <!--${QV-impl::QACTIVE_EQUEUE_WAIT_}-->
- <operation name="QACTIVE_EQUEUE_WAIT_" type="" visibility="0x03" properties="0x00">
- <documentation>* QV native event queue waiting</documentation>
- <!--${QV-impl::QACTIVE_EQUEUE_W~::me_}-->
- <parameter name="me_" type="QActive *"/>
- <code>\
- Q_ASSERT_ID(0, (me_)->eQueue.frontEvt != (QEvt *)0)</code>
- </operation>
- <!--${QV-impl::QACTIVE_EQUEUE_SIGNAL_}-->
- <operation name="QACTIVE_EQUEUE_SIGNAL_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QV native event queue signaling */</documentation>
- <!--${QV-impl::QACTIVE_EQUEUE_S~::me_}-->
- <parameter name="me_" type="QActive *"/>
- <code>\
- QPSet_insert(&QF_readySet_, (uint_fast8_t)(me_)->prio)</code>
- </operation>
- </package>
- <!--${QK}-->
- <package name="QK" stereotype="0x05">
- <!--${QK::QK-base}-->
- <package name="QK-base" stereotype="0x02" namespace="QK_">
- <!--${QK::QK-base::schedLock}-->
- <operation name="schedLock" type="QSchedStatus" visibility="0x00" properties="0x01">
- <documentation>/*! QK selective scheduler lock
- * @static @public @memberof QK
- *
- * @details
- * This function locks the QK scheduler to the specified ceiling.
- *
- * @param[in] ceiling preemption ceiling to which the QK scheduler
- * needs to be locked
- *
- * @returns
- * The previous QK Scheduler lock status, which is to be used to unlock
- * the scheduler by restoring its previous lock status in
- * QK_schedUnlock().
- *
- * @precondition{qk,600}
- * - The QK scheduler lock cannot be called from an ISR
- *
- * @note
- * QK_schedLock() must be always followed by the corresponding
- * QK_schedUnlock().
- *
- * @sa QK_schedUnlock()
- *
- * @usage
- * The following example shows how to lock and unlock the QK scheduler:
- * @include qk_lock.c
- */
- /*! @static @public @memberof QK */</documentation>
- <!--${QK::QK-base::schedLock::ceiling}-->
- <parameter name="ceiling" type="uint_fast8_t const"/>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- Q_REQUIRE_ID(600, !QK_ISR_CONTEXT_());
- /* first store the previous lock prio */
- QSchedStatus stat;
- if (ceiling > QK_attr_.lockCeil) { /* raising the lock ceiling? */
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_LOCK, 0U)
- QS_TIME_PRE_(); /* timestamp */
- /* the previous lock ceiling & new lock ceiling */
- QS_2U8_PRE_(QK_attr_.lockCeil, (uint8_t)ceiling);
- QS_END_NOCRIT_PRE_()
- /* previous status of the lock */
- stat = (QSchedStatus)QK_attr_.lockHolder;
- stat |= (QSchedStatus)QK_attr_.lockCeil << 8U;
- /* new status of the lock */
- QK_attr_.lockHolder = QK_attr_.actPrio;
- QK_attr_.lockCeil = (uint8_t)ceiling;
- }
- else {
- stat = 0xFFU; /* scheduler not locked */
- }
- QF_CRIT_X_();
- return stat; /* return the status to be saved in a stack variable */</code>
- </operation>
- <!--${QK::QK-base::schedUnlock}-->
- <operation name="schedUnlock" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QK selective scheduler unlock
- * @static @public @memberof QK
- *
- * @details
- * This function unlocks the QK scheduler to the previous status.
- *
- * @param[in] stat previous QK Scheduler lock status returned from
- * QK_schedLock()
- *
- * @precondition{qk,700}
- * - the QK scheduler cannot be unlocked: from the ISR context
- * - the current lock ceiling must be greater than the previous
- *
- * @note
- * QK_schedUnlock() must always follow the corresponding
- * QK_schedLock().
- *
- * @sa QK_schedLock()
- *
- * @usage
- * The following example shows how to lock and unlock the QK scheduler:
- * @include qk_lock.c
- */
- /*! @static @public @memberof QK */</documentation>
- <!--${QK::QK-base::schedUnlock::stat}-->
- <parameter name="stat" type="QSchedStatus const"/>
- <code>/* has the scheduler been actually locked by the last QK_schedLock()? */
- if (stat != 0xFFU) {
- uint8_t const lockCeil = QK_attr_.lockCeil;
- uint8_t const prevCeil = (uint8_t)(stat >> 8U);
- QF_CRIT_STAT_
- QF_CRIT_E_();
- Q_REQUIRE_ID(700, (!QK_ISR_CONTEXT_())
- && (lockCeil > prevCeil));
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_UNLOCK, 0U)
- QS_TIME_PRE_(); /* timestamp */
- // current lock ceiling (old), previous lock ceiling (new) */
- QS_2U8_PRE_(lockCeil, prevCeil);
- QS_END_NOCRIT_PRE_()
- /* restore the previous lock ceiling and lock holder */
- QK_attr_.lockCeil = prevCeil;
- QK_attr_.lockHolder = (uint8_t)(stat & 0xFFU);
- /* find if any AOs should be run after unlocking the scheduler */
- if (QK_sched_() != 0U) { /* preemption needed? */
- QK_activate_(); /* activate any unlocked AOs */
- }
- QF_CRIT_X_();
- }</code>
- </operation>
- <!--${QK::QK-base::onIdle}-->
- <operation name="onIdle" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QK idle callback (customized in BSPs for QK)
- * @static @public @memberof QK
- *
- * @details
- * QK_onIdle() is called continuously by the QK idle loop. This callback
- * gives the application an opportunity to enter a power-saving CPU mode,
- * or perform some other idle processing.
- *
- * @note
- * QK_onIdle() is invoked with interrupts enabled and must also return with
- * interrupts enabled.
- */
- /*! @static @public @memberof QK */</documentation>
- </operation>
- </package>
- <!--${QK::QF-cust}-->
- <package name="QF-cust" stereotype="0x02" namespace="QF_">
- <!--${QK::QF-cust::init}-->
- <operation name="init" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QF initialization for QK
- * @static @public @memberof QF
- */
- /*! @static @public @memberof QF */</documentation>
- <code>#if (QF_MAX_EPOOL > 0U)
- QF_maxPool_ = 0U;
- #endif
- QF_bzero(&QTimeEvt_timeEvtHead_[0], sizeof(QTimeEvt_timeEvtHead_));
- QF_bzero(&QActive_registry_[0], sizeof(QActive_registry_));
- QF_bzero(&QF_readySet_, sizeof(QF_readySet_));
- QF_bzero(&QK_attr_, sizeof(QK_attr_));
- /* setup the QK scheduler as initially locked and not running */
- QK_attr_.lockCeil = (QF_MAX_ACTIVE + 1U); /* scheduler locked */
- /* QK idle AO object (const in ROM) */
- static QActive const idle_ao = { (struct QHsmVtable const *)0 };
- /* register the idle AO object (cast 'const' away) */
- QActive_registry_[0] = (QActive *)&idle_ao;
- #ifdef QK_INIT
- QK_INIT(); /* port-specific initialization of the QK kernel */
- #endif</code>
- </operation>
- <!--${QK::QF-cust::stop}-->
- <operation name="stop" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Stop the QF customization for QK
- * @static @public @memberof QF
- */
- /*! @static @public @memberof QF */</documentation>
- <code>QF_onCleanup(); /* application-specific cleanup callback */
- /* nothing else to do for the preemptive QK kernel */</code>
- </operation>
- <!--${QK::QF-cust::run}-->
- <operation name="run" type="int_t" visibility="0x00" properties="0x01">
- <documentation>/*! QF_run() customization for QK kernel
- * @static @public @memberof QF
- */
- /*! @static @public @memberof QF */</documentation>
- <code>#ifdef Q_SPY
- /* produce the QS_QF_RUN trace record */
- QF_INT_DISABLE();
- QS_beginRec_((uint_fast8_t)QS_QF_RUN);
- QS_endRec_();
- QF_INT_ENABLE();
- #endif /* Q_SPY */
- QF_onStartup(); /* application-specific startup callback */
- QF_INT_DISABLE();
- QK_attr_.lockCeil = 0U; /* unlock the QK scheduler */
- /* activate AOs to process events posted so far */
- if (QK_sched_() != 0U) {
- QK_activate_();
- }
- #ifdef QK_START
- QK_START(); /* port-specific startup of the QK kernel */
- #endif
- QF_INT_ENABLE();
- for (;;) { /* QK idle loop... */
- QK_onIdle(); /* application-specific QK on-idle callback */
- }
- #ifdef __GNUC__
- return 0;
- #endif</code>
- </operation>
- </package>
- <!--${QK::QActive}-->
- <class name="QActive">
- <documentation>/*! QActive active object class customization for QK */</documentation>
- <!--${QK::QActive::start_}-->
- <operation name="start_" type="void" visibility="0x00" properties="0x04">
- <documentation>/*! Starts execution of an active object and registers the object
- * with the framework customized for the QK kernel
- * @public @memberof QActive
- *
- * @precondition{qk,300}
- * - stack storage must not be provided because the QK kernel
- * does not need per-AO stacks.
- */
- /*! @public @memberof QActive */</documentation>
- <!--${QK::QActive::start_::prioSpec}-->
- <parameter name="prioSpec" type="QPrioSpec const"/>
- <!--${QK::QActive::start_::qSto}-->
- <parameter name="qSto" type="QEvt const * * const"/>
- <!--${QK::QActive::start_::qLen}-->
- <parameter name="qLen" type="uint_fast16_t const"/>
- <!--${QK::QActive::start_::stkSto}-->
- <parameter name="stkSto" type="void * const"/>
- <!--${QK::QActive::start_::stkSize}-->
- <parameter name="stkSize" type="uint_fast16_t const"/>
- <!--${QK::QActive::start_::par}-->
- <parameter name="par" type="void const * const"/>
- <code>Q_UNUSED_PAR(stkSto); /* not needed in QK */
- Q_UNUSED_PAR(stkSize); /* not needed in QK */
- Q_REQUIRE_ID(300, (!QK_ISR_CONTEXT_())
- && (stkSto == (void *)0));
- me->prio = (uint8_t)(prioSpec & 0xFFU); /* QF-priority of the AO */
- me->pthre = (uint8_t)(prioSpec >> 8U); /* preemption-threshold */
- QActive_register_(me); /* make QF aware of this active object */
- QEQueue_init(&me->eQueue, qSto, qLen); /* init the built-in queue */
- QHSM_INIT(&me->super, par, me->prio); /* top-most initial tran. */
- QS_FLUSH(); /* flush the trace buffer to the host */
- /* See if this AO needs to be scheduled if QK is already running */
- QF_CRIT_STAT_
- QF_CRIT_E_();
- if (QK_sched_() != 0U) { /* activation needed? */
- QK_activate_();
- }
- QF_CRIT_X_();</code>
- </operation>
- </class>
- <!--${QK::QK-extern-C}-->
- <package name="QK-extern-C" stereotype="0x02" namespace="QK_">
- <!--${QK::QK-extern-C::Attr}-->
- <attribute name="Attr" type="typedef struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief QK preemptive non-blocking kernel
- * @class QK
- */</documentation>
- <code>{
- uint8_t volatile actPrio; /*!< QF prio of the active AO */
- uint8_t volatile nextPrio; /*!< QF prio of the next AO to execute */
- uint8_t volatile actThre; /*!< active preemption-threshold */
- uint8_t volatile lockCeil; /*!< lock preemption-ceiling (0==no-lock) */
- uint8_t volatile lockHolder; /*!< QF prio of the AO holding the lock */
- } QK;</code>
- </attribute>
- <!--${QK::QK-extern-C::attr_}-->
- <attribute name="attr_" type="QK" visibility="0x00" properties="0x00">
- <documentation>/*! attributes of the QK kernel
- * @static @private @memberof QK
- */
- /*! @static @private @memberof QK */</documentation>
- </attribute>
- <!--${QK::QK-extern-C::sched_}-->
- <operation name="sched_" type="uint_fast8_t" visibility="0x00" properties="0x00">
- <documentation>/*! QK scheduler finds the highest-priority AO ready to run
- * @static @private @memberof QK
- *
- * @details
- * The QK scheduler finds out the priority of the highest-priority AO
- * that (1) has events to process and (2) has priority that is above the
- * current priority.
- *
- * @returns
- * The QF-priority of the next active object to activate, or zero
- * if no activation of AO is needed.
- *
- * @attention
- * QK_sched_() must be always called with interrupts **disabled** and
- * returns with interrupts **disabled**.
- */
- /*! @static @private @memberof QK */</documentation>
- <code>uint_fast8_t p;
- if (QPSet_isEmpty(&QF_readySet_)) {
- p = 0U; /* no activation needed */
- }
- else {
- /* find the highest-prio AO with non-empty event queue */
- p = QPSet_findMax(&QF_readySet_);
- /* is the AO's priority below the active preemption-threshold? */
- if (p <= QK_attr_.actThre) {
- p = 0U; /* no activation needed */
- }
- /* is the AO's priority below the lock-ceiling? */
- else if (p <= QK_attr_.lockCeil) {
- p = 0U; /* no activation needed */
- }
- else {
- QK_attr_.nextPrio = (uint8_t)p; /* next AO to run */
- }
- }
- return p;</code>
- </operation>
- <!--${QK::QK-extern-C::activate_}-->
- <operation name="activate_" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! QK activator activates the next active object. The activated AO preempts
- * the currently executing AOs.
- * @static @private @memberof QK
- *
- * @details
- * QK_activate_() activates ready-to run AOs that are above the initial
- * preemption-threshold.
- *
- * @precondition{qk,500}
- * - QK_attr_.actPrio and QK_attr_.nextPrio must be in range
- *
- * @attention
- * QK_activate_() must be always called with interrupts **disabled** and
- * returns with interrupts **disabled**.
- */
- /*! @static @private @memberof QK */</documentation>
- <code>uint8_t const prio_in = QK_attr_.actPrio; /* saved initial priority */
- uint8_t p = QK_attr_.nextPrio; /* next prio to run */
- QK_attr_.nextPrio = 0U; /* clear for the next time */
- Q_REQUIRE_ID(500, (prio_in <= QF_MAX_ACTIVE)
- && (0U < p) && (p <= QF_MAX_ACTIVE));
- #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
- uint8_t pprev = prio_in;
- #endif /* QF_ON_CONTEXT_SW || Q_SPY */
- /* loop until no more ready-to-run AOs of higher pthre than the initial */
- QActive *a;
- do {
- a = QActive_registry_[p]; /* obtain the pointer to the AO */
- Q_ASSERT_ID(505, a != (QActive *)0); /* the AO must be registered */
- /* set new active priority and preemption-threshold */
- QK_attr_.actPrio = p;
- QK_attr_.actThre = a->pthre;
- #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
- if (p != pprev) { /* changing threads? */
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_NEXT, p)
- QS_TIME_PRE_(); /* timestamp */
- QS_2U8_PRE_(p, /* priority of the scheduled AO */
- pprev); /* previous priority */
- QS_END_NOCRIT_PRE_()
- #ifdef QF_ON_CONTEXT_SW
- QF_onContextSw(((pprev != 0U)
- ? QActive_registry_[pprev]
- : (QActive *)0), a);
- #endif /* QF_ON_CONTEXT_SW */
- pprev = p; /* update previous priority */
- }
- #endif /* QF_ON_CONTEXT_SW || Q_SPY */
- QF_INT_ENABLE(); /* unconditionally enable interrupts */
- /* perform the run-to-completion (RTC) step...
- * 1. retrieve the event from the AO's event queue, which by this
- * time must be non-empty and QActive_get_() asserts it.
- * 2. dispatch the event to the AO's state machine.
- * 3. determine if event is garbage and collect it if so
- */
- QEvt const * const e = QActive_get_(a);
- QHSM_DISPATCH(&a->super, e, p);
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e);
- #endif
- /* determine the next highest-priority AO ready to run... */
- QF_INT_DISABLE(); /* unconditionally disable interrupts */
- if (a->eQueue.frontEvt == (QEvt *)0) { /* empty queue? */
- QPSet_remove(&QF_readySet_, p);
- }
- if (QPSet_isEmpty(&QF_readySet_)) {
- p = 0U; /* no activation needed */
- }
- else {
- /* find new highest-prio AO ready to run... */
- p = (uint8_t)QPSet_findMax(&QF_readySet_);
- /* is the new priority below the initial preemption-threshold? */
- if (p <= QActive_registry_[prio_in]->pthre) {
- p = 0U; /* no activation needed */
- }
- /* is the AO's priority below the lock preemption-ceiling? */
- else if (p <= QK_attr_.lockCeil) {
- p = 0U; /* no activation needed */
- }
- else {
- Q_ASSERT_ID(510, p <= QF_MAX_ACTIVE);
- }
- }
- } while (p != 0U);
- /* restore the active priority and preemption-threshold */
- QK_attr_.actPrio = prio_in;
- QK_attr_.actThre = QActive_registry_[prio_in]->pthre;
- #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
- if (prio_in != 0U) { /* resuming an active object? */
- a = QActive_registry_[prio_in]; /* pointer to the preempted AO */
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_NEXT, prio_in)
- QS_TIME_PRE_(); /* timestamp */
- /* priority of the resumed AO, previous priority */
- QS_2U8_PRE_(prio_in, pprev);
- QS_END_NOCRIT_PRE_()
- }
- else { /* resuming priority==0 --> idle */
- a = (QActive *)0; /* QK idle loop */
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_IDLE, pprev)
- QS_TIME_PRE_(); /* timestamp */
- QS_U8_PRE_(pprev); /* previous priority */
- QS_END_NOCRIT_PRE_()
- }
- #ifdef QF_ON_CONTEXT_SW
- QF_onContextSw(QActive_registry_[pprev], a);
- #endif /* QF_ON_CONTEXT_SW */
- #endif /* QF_ON_CONTEXT_SW || Q_SPY */</code>
- </operation>
- </package>
- </package>
- <!--${QK-impl}-->
- <package name="QK-impl" stereotype="0x02">
- <!--${QK-impl::QK_ISR_CONTEXT_}-->
- <operation name="QK_ISR_CONTEXT_?ndef QK_ISR_CONTEXT_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Internal macro that reports the execution context (ISR vs. thread)
- *
- * @returns true if the code executes in the ISR context and false
- * otherwise
- */</documentation>
- <code>(QF_intNest_ != 0U)</code>
- </operation>
- <!--${QK-impl::QF_SCHED_STAT_}-->
- <attribute name="QF_SCHED_STAT_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QK scheduler lock status */</documentation>
- <code>QSchedStatus lockStat_;</code>
- </attribute>
- <!--${QK-impl::QF_SCHED_LOCK_}-->
- <operation name="QF_SCHED_LOCK_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QK selective scheduler locking */</documentation>
- <!--${QK-impl::QF_SCHED_LOCK_::ceil_}-->
- <parameter name="ceil_" type="uint_fast8_t"/>
- <code>do { \
- if (QK_ISR_CONTEXT_()) { \
- lockStat_ = 0xFFU; \
- } else { \
- lockStat_ = QK_schedLock((ceil_)); \
- } \
- } while (false)</code>
- </operation>
- <!--${QK-impl::QF_SCHED_UNLOCK_}-->
- <operation name="QF_SCHED_UNLOCK_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QK selective scheduler unlocking */</documentation>
- <code>do { \
- if (lockStat_ != 0xFFU) { \
- QK_schedUnlock(lockStat_); \
- } \
- } while (false)</code>
- </operation>
- <!--${QK-impl::QACTIVE_EQUEUE_WAIT_}-->
- <operation name="QACTIVE_EQUEUE_WAIT_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QK native event queue waiting */</documentation>
- <!--${QK-impl::QACTIVE_EQUEUE_W~::me_}-->
- <parameter name="me_" type="QActive *"/>
- <code>\
- (Q_ASSERT_ID(110, (me_)->eQueue.frontEvt != (QEvt *)0))</code>
- </operation>
- <!--${QK-impl::QACTIVE_EQUEUE_SIGNAL_}-->
- <operation name="QACTIVE_EQUEUE_SIGNAL_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QK native event queue signaling */</documentation>
- <!--${QK-impl::QACTIVE_EQUEUE_S~::me_}-->
- <parameter name="me_" type="QActive *"/>
- <code>do { \
- QPSet_insert(&QF_readySet_, (uint_fast8_t)(me_)->prio); \
- if (!QK_ISR_CONTEXT_()) { \
- if (QK_sched_() != 0U) { \
- QK_activate_(); \
- } \
- } \
- } while (false)</code>
- </operation>
- </package>
- <!--${QXK}-->
- <package name="QXK" stereotype="0x05">
- <!--${QXK::QXK-base}-->
- <package name="QXK-base" stereotype="0x02" namespace="QXK_">
- <!--${QXK::QXK-base::onIdle}-->
- <operation name="onIdle" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QXK idle callback (customized in BSPs for QXK)
- * @static @public @memberof QXK
- *
- * @details
- * QXK_onIdle() is called continuously by the QXK idle thread. This callback
- * gives the application an opportunity to enter a power-saving CPU mode,
- * or perform some other idle processing.
- *
- * @note
- * QXK_onIdle() is invoked with interrupts enabled and must also return with
- * interrupts enabled.
- */
- /*! @static @public @memberof QXK */</documentation>
- </operation>
- <!--${QXK::QXK-base::schedLock}-->
- <operation name="schedLock" type="QSchedStatus" visibility="0x00" properties="0x01">
- <documentation>/*! QXK Scheduler lock
- * @static @public @memberof QXK
- *
- * @details
- * This function locks the QXK scheduler to the specified ceiling.
- *
- * @param[in] ceiling preemption ceiling to which the QXK scheduler
- * needs to be locked
- *
- * @returns
- * The previous QXK Scheduler lock status, which is to be used to unlock
- * the scheduler by restoring its previous lock status in
- * QXK_schedUnlock().
- *
- * @precondition{qxk,400}
- * - the QXK scheduler lock cannot be called from an ISR
- *
- * @note
- * A QXK scheduler can be locked from both basic threads (AOs) and
- * extended threads and the scheduler locks can nest.
- *
- * @note
- * QXK_schedLock() must be always followed by the corresponding
- * QXK_schedUnlock().
- *
- * @attention
- * QXK will fire an assertion if a thread holding the lock attempts
- * to block.
- *
- * @sa QXK_schedUnlock()
- *
- * @usage
- * The following example shows how to lock and unlock the QXK scheduler:
- * @include qxk_lock.c
- */
- /*! @static @public @memberof QXK */</documentation>
- <!--${QXK::QXK-base::schedLock::ceiling}-->
- <parameter name="ceiling" type="uint_fast8_t const"/>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- Q_REQUIRE_ID(400, !QXK_ISR_CONTEXT_());
- QSchedStatus stat; /* saved lock status to be returned */
- /* is the lock ceiling being raised? */
- if (ceiling > (uint_fast8_t)QXK_attr_.lockCeil) {
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_LOCK, 0U)
- QS_TIME_PRE_(); /* timestamp */
- /* the previous lock ceiling & new lock ceiling */
- QS_2U8_PRE_(QXK_attr_.lockCeil, (uint8_t)ceiling);
- QS_END_NOCRIT_PRE_()
- /* previous status of the lock */
- stat = (QSchedStatus)QXK_attr_.lockHolder;
- stat |= (QSchedStatus)QXK_attr_.lockCeil << 8U;
- /* new status of the lock */
- QXK_attr_.lockHolder = (QXK_attr_.curr != (QActive *)0)
- ? QXK_attr_.curr->prio
- : 0U;
- QXK_attr_.lockCeil = (uint8_t)ceiling;
- }
- else {
- stat = 0xFFU; /* scheduler not locked */
- }
- QF_CRIT_X_();
- return stat; /* return the status to be saved in a stack variable */</code>
- </operation>
- <!--${QXK::QXK-base::schedUnlock}-->
- <operation name="schedUnlock" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QXK Scheduler unlock
- * @static @public @memberof QXK
- *
- * @details
- * This function unlocks the QXK scheduler to the previous status.
- *
- * @param[in] stat previous QXK Scheduler lock status returned from
- * QXK_schedLock()
- *
- * @precondition{qxk,500}
- * - the QXK scheduler cannot be unlocked from the ISR context
- * @precondition{qxk,501}
- * - the current lock ceiling must be greater than the previous
- *
- * @note
- * A QXK scheduler can be locked from both basic threads (AOs) and
- * extended threads and the scheduler locks can nest.
- *
- * @note
- * QXK_schedUnlock() must always follow the corresponding QXK_schedLock().
- *
- * @usage
- * The following example shows how to lock and unlock the QXK scheduler:
- * @include qxk_lock.c
- */
- /*! @static @public @memberof QXK */</documentation>
- <!--${QXK::QXK-base::schedUnlock::stat}-->
- <parameter name="stat" type="QSchedStatus const"/>
- <code>/* has the scheduler been actually locked by the last QXK_schedLock()? */
- if (stat != 0xFFU) {
- uint8_t const prevCeil = (uint8_t)(stat >> 8U);
- QF_CRIT_STAT_
- QF_CRIT_E_();
- Q_REQUIRE_ID(500, !QXK_ISR_CONTEXT_());
- Q_REQUIRE_ID(501, QXK_attr_.lockCeil > prevCeil);
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_UNLOCK, 0U)
- QS_TIME_PRE_(); /* timestamp */
- /* ceiling before unlocking & prio after unlocking */
- QS_2U8_PRE_(QXK_attr_.lockCeil, prevCeil);
- QS_END_NOCRIT_PRE_()
- /* restore the previous lock ceiling and lock holder */
- QXK_attr_.lockCeil = prevCeil;
- QXK_attr_.lockHolder = (uint8_t)(stat & 0xFFU);
- /* find if any threads should be run after unlocking the scheduler */
- if (QXK_sched_() != 0U) { /* activation needed? */
- QXK_activate_(); /* synchronously activate basic-thred(s) */
- }
- QF_CRIT_X_();
- }</code>
- </operation>
- <!--${QXK::QXK-base::Timeouts}-->
- <attribute name="Timeouts" type="enum" visibility="0x04" properties="0x00">
- <documentation>/*! timeout signals for extended threads
- * @static @private @memberof QXK
- */
- /*! @static @private @memberof QXK */</documentation>
- <code>{
- QXK_DELAY_SIG = 1,
- QXK_TIMEOUT_SIG
- };</code>
- </attribute>
- </package>
- <!--${QXK::QF-cust}-->
- <package name="QF-cust" stereotype="0x02" namespace="QF_">
- <!--${QXK::QF-cust::init}-->
- <operation name="init" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QF initialization for QXK
- * @static @public @memberof QF
- */
- /*! @static @public @memberof QF */</documentation>
- <code>#if (QF_MAX_EPOOL > 0U)
- QF_maxPool_ = 0U;
- #endif
- QF_bzero(&QTimeEvt_timeEvtHead_[0], sizeof(QTimeEvt_timeEvtHead_));
- QF_bzero(&QActive_registry_[0], sizeof(QActive_registry_));
- QF_bzero(&QF_readySet_, sizeof(QF_readySet_));
- QF_bzero(&QXK_attr_, sizeof(QXK_attr_));
- /* setup the QXK scheduler as initially locked and not running */
- QXK_attr_.lockCeil = (QF_MAX_ACTIVE + 1U); /* scheduler locked */
- /* QXK idle AO object (const in ROM) */
- static QActive const idle_ao = { (struct QHsmVtable const *)0 };
- /* register the idle AO object (cast 'const' away) */
- QActive_registry_[0] = (QActive *)&idle_ao;
- QXK_attr_.prev = QActive_registry_[0];
- #ifdef QXK_INIT
- QXK_INIT(); /* port-specific initialization of the QXK kernel */
- #endif</code>
- </operation>
- <!--${QXK::QF-cust::stop}-->
- <operation name="stop" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Stop the QF customization for QXK
- * @static @public @memberof QF
- */
- /*! @static @public @memberof QF */</documentation>
- <code>QF_onCleanup(); /* application-specific cleanup callback */
- /* nothing else to do for the dual-mode QXK kernel */</code>
- </operation>
- <!--${QXK::QF-cust::run}-->
- <operation name="run" type="int_t" visibility="0x00" properties="0x01">
- <documentation>/*! QF_run() customization for QXK kernel
- * @static @public @memberof QF
- */
- /*! @static @public @memberof QF */</documentation>
- <code>#ifdef Q_SPY
- QS_SIG_DICTIONARY(QXK_DELAY_SIG, (void *)0);
- QS_SIG_DICTIONARY(QXK_TIMEOUT_SIG, (void *)0);
- /* produce the QS_QF_RUN trace record */
- QF_INT_DISABLE();
- QS_beginRec_((uint_fast8_t)QS_QF_RUN);
- QS_endRec_();
- QF_INT_ENABLE();
- #endif /* Q_SPY */
- QF_onStartup(); /* application-specific startup callback */
- QF_INT_DISABLE();
- QXK_attr_.lockCeil = 0U; /* unlock the QXK scheduler */
- /* activate AOs to process events posted so far */
- if (QXK_sched_() != 0U) {
- QXK_activate_();
- }
- #ifdef QXK_START
- QXK_START(); /* port-specific startup of the QXK kernel */
- #endif
- QF_INT_ENABLE();
- for (;;) { /* QXK idle loop... */
- QXK_onIdle(); /* application-specific QXK idle callback */
- }
- #ifdef __GNUC__
- return 0;
- #endif</code>
- </operation>
- </package>
- <!--${QXK::QXThread}-->
- <class name="QXThread" superclass="QF::QActive">
- <documentation>/*! @brief eXtended (blocking) thread of the QXK preemptive kernel
- * @class QXThread
- * @extends QActive
- *
- * @details
- * ::QXThread represents the eXtended (blocking) thread of the QXK
- * kernel. Each extended thread in the application must be represented
- * by the corresponding ::QXThread instance
- *
- * @note
- * Typically, ::QXThread is instantiated directly in the application code.
- * The customization of the thread occurs in the QXThread_ctor(), where you
- * provide the thread-handler function as the parameter.
- *
- * @usage
- * The following example illustrates how to instantiate and use an extended
- * thread in your application.
- * @include qxk_thread.c
- */</documentation>
- <!--${QXK::QXThread::timeEvt}-->
- <attribute name="timeEvt" type="QTimeEvt" visibility="0x02" properties="0x00">
- <documentation>/*! time event to handle blocking timeouts */</documentation>
- </attribute>
- <!--${QXK::QXThread::dummy}-->
- <attribute name="dummy" type="QXThread const *" visibility="0x02" properties="0x01">
- <documentation>/*! dummy static to force generation of "struct QXThread" */</documentation>
- </attribute>
- <!--${QXK::QXThread::ctor}-->
- <operation name="ctor" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! constructor of an extended-thread
- * @public @memberof QXThread
- *
- * @details
- * Performs the first step of QXThread initialization by assigning the
- * thread-handler function and the tick rate at which it will handle
- * the timeouts.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] handler the thread-handler function
- * @param[in] tickRate the ticking rate for timeouts in this thread
- * (see QXThread_delay() and QTIMEEVT_TICK_X())
- *
- * @note
- * Must be called only ONCE before QXTHREAD_START().
- *
- * @usage
- * The following example illustrates how to invoke QXThread_ctor() in the
- * main() function
- *
- * @include
- * qxk_thread_ctor.c
- */
- /*! @public @memberof QXThread */</documentation>
- <!--${QXK::QXThread::ctor::handler}-->
- <parameter name="handler" type="QXThreadHandler const"/>
- <!--${QXK::QXThread::ctor::tickRate}-->
- <parameter name="tickRate" type="uint_fast8_t const"/>
- <code>static QXThreadVtable const vtable = { /* QXThread virtual table */
- { &QXThread_init_, /* not used in QXThread */
- &QXThread_dispatch_ /* not used in QXThread */
- #ifdef Q_SPY
- ,&QHsm_getStateHandler_ /* not used in QXThread */
- #endif
- },
- &QXThread_start_,
- &QXThread_post_,
- &QXThread_postLIFO_
- };
- union QHsmAttr tmp;
- tmp.thr = handler;
- QActive_ctor(&me->super, tmp.fun); /* superclass' ctor */
- me->super.super.vptr = &vtable.super; /* hook to QXThread vtable */
- me->super.super.state.act = Q_ACTION_CAST(0); /*mark as extended thread */
- /* construct the time event member added in the QXThread class */
- QTimeEvt_ctorX(&me->timeEvt, &me->super,
- (enum_t)QXK_DELAY_SIG, tickRate);</code>
- </operation>
- <!--${QXK::QXThread::delay}-->
- <operation name="delay" type="bool" visibility="0x00" properties="0x01">
- <documentation>/*! delay (block) the current extended thread for a specified # ticks
- * @static @public @memberof QXThread
- *
- * @details
- * Blocking delay for the number of clock tick at the associated tick rate.
- *
- * @param[in] nTicks number of clock ticks (at the associated rate)
- * to wait for the event to arrive.
- *
- * @returns
- * 'true' if delay has expired, 'false' if it delay was canceled with
- * QXThread_delayCancel().
- *
- * @precondition{qxk_xthr,800}
- * - must NOT be called from an ISR;
- * - number of ticks cannot be zero
- * - be called from an extended thread;
- * - the thread must NOT be already blocked on any object.
- * @precondition{qxk_xthr,801}
- * - the thread must NOT be holding a scheduler lock.
- *
- * @note
- * For the delay to work, the QTIMEEVT_TICK_X() macro needs to be called
- * periodically at the associated clock tick rate.
- *
- * @sa QXThread_ctor()
- * @sa QTIMEEVT_TICK_X()
- */
- /*! @public @memberof QXThread */</documentation>
- <!--${QXK::QXThread::delay::nTicks}-->
- <parameter name="nTicks" type="uint_fast16_t const"/>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QXThread * const thr = QXTHREAD_CAST_(QXK_attr_.curr);
- Q_REQUIRE_ID(800, (!QXK_ISR_CONTEXT_()) /* can't block inside an ISR */
- && (nTicks != 0U) /* number of ticks cannot be zero */
- && (thr != (QXThread *)0) /* current thread must be extended */
- && (thr->super.super.temp.obj == (QMState *)0)); /* !blocked */
- Q_REQUIRE_ID(801, QXK_attr_.lockHolder != thr->super.prio);
- /* remember the blocking object */
- thr->super.super.temp.obj = QXK_PTR_CAST_(QMState const*, &thr->timeEvt);
- QXThread_teArm_(thr, (enum_t)QXK_DELAY_SIG, nTicks);
- QXThread_block_(thr);
- QF_CRIT_X_();
- QF_CRIT_EXIT_NOP(); /* BLOCK here */
- QF_CRIT_E_();
- /* the blocking object must be the time event */
- Q_ENSURE_ID(890, thr->super.super.temp.obj
- == QXK_PTR_CAST_(QMState const*, &thr->timeEvt));
- thr->super.super.temp.obj = (QMState *)0; /* clear */
- QF_CRIT_X_();
- /* signal of zero means that the time event was posted without
- * being canceled.
- */
- return thr->timeEvt.super.sig == 0U;</code>
- </operation>
- <!--${QXK::QXThread::delayCancel}-->
- <operation name="delayCancel" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! cancel the delay
- * @public @memberof QXThread
- *
- * @details
- * Cancel the blocking delay and cause return from the QXThread_delay()
- * function.
- *
- * @returns
- * "true" if the thread was actually blocked on QXThread_delay() and
- * "false" otherwise.
- */
- /*! @public @memberof QXThread */</documentation>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- bool wasArmed;
- if (me->super.super.temp.obj == QXK_PTR_CAST_(QMState*, &me->timeEvt)) {
- wasArmed = QXThread_teDisarm_(me);
- QXThread_unblock_(me);
- }
- else {
- wasArmed = false;
- }
- QF_CRIT_X_();
- return wasArmed;</code>
- </operation>
- <!--${QXK::QXThread::queueGet}-->
- <operation name="queueGet" type="QEvt const *" visibility="0x00" properties="0x01">
- <documentation>/*! obtain a message from the private message queue (block if no messages)
- * @static @public @memberof QXThread
- *
- * @details
- * The QXThread_queueGet() operation allows the calling extended thread to
- * receive QP events directly into its own built-in event queue from an ISR,
- * basic thread (AO), or another extended thread.
- *
- * If QXThread_queueGet() is called when no events are present in the
- * thread's private event queue, the operation blocks the current extended
- * thread until either an event is received, or a user-specified timeout
- * expires.
- *
- * @param[in] nTicks number of clock ticks (at the associated rate)
- * to wait for the event to arrive. The value of
- * ::QXTHREAD_NO_TIMEOUT indicates that no timeout will
- * occur and the queue will block indefinitely.
- * @returns
- * A pointer to the event. If the pointer is not NULL, the event was delivered.
- * Otherwise the event pointer of NULL indicates that the queue has timed out.
- *
- * @precondition{qxk_xthr,500}
- * - must NOT be called from an ISR;
- * - be called from an extended thread;
- * - the thread must NOT be already blocked on any object.
- * @precondition{qxk_xthr,501}
- * - the thread must NOT be holding a scheduler lock.
- */
- /*! @static @public @memberof QXThread */</documentation>
- <!--${QXK::QXThread::queueGet::nTicks}-->
- <parameter name="nTicks" type="uint_fast16_t const"/>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QXThread * const thr = QXTHREAD_CAST_(QXK_attr_.curr);
- Q_REQUIRE_ID(500, (!QXK_ISR_CONTEXT_()) /* can't block inside an ISR */
- && (thr != (QXThread *)0) /* current thread must be extended */
- && (thr->super.super.temp.obj == (QMState *)0)); /* !blocked */
- Q_REQUIRE_ID(501, QXK_attr_.lockHolder != thr->super.prio);
- /* is the queue empty? */
- if (thr->super.eQueue.frontEvt == (QEvt *)0) {
- /* remember the blocking object (the thread's queue) */
- thr->super.super.temp.obj
- = QXK_PTR_CAST_(QMState const*, &thr->super.eQueue);
- QXThread_teArm_(thr, (enum_t)QXK_TIMEOUT_SIG, nTicks);
- QPSet_remove(&QF_readySet_, (uint_fast8_t)thr->super.prio);
- (void)QXK_sched_(); /* schedule other threads */
- QF_CRIT_X_();
- QF_CRIT_EXIT_NOP(); /* BLOCK here */
- QF_CRIT_E_();
- /* the blocking object must be this queue */
- Q_ASSERT_ID(510, thr->super.super.temp.obj
- == QXK_PTR_CAST_(QMState const*, &thr->super.eQueue));
- thr->super.super.temp.obj = (QMState *)0; /* clear */
- }
- /* is the queue not empty? */
- QEvt const *e;
- if (thr->super.eQueue.frontEvt != (QEvt *)0) {
- e = thr->super.eQueue.frontEvt; /* remove from the front */
- QEQueueCtr const nFree= thr->super.eQueue.nFree + 1U;
- thr->super.eQueue.nFree = nFree; /* update the number of free */
- /* any events in the ring buffer? */
- if (nFree <= thr->super.eQueue.end) {
- /* remove event from the tail */
- thr->super.eQueue.frontEvt =
- thr->super.eQueue.ring[thr->super.eQueue.tail];
- if (thr->super.eQueue.tail == 0U) { /* need to wrap? */
- thr->super.eQueue.tail = thr->super.eQueue.end; /* wrap */
- }
- --thr->super.eQueue.tail;
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET, thr->super.prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(&thr->super); /* this active object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* number of free entries */
- QS_END_NOCRIT_PRE_()
- }
- else {
- thr->super.eQueue.frontEvt = (QEvt *)0; /* empty queue */
- /* all entries in the queue must be free (+1 for fronEvt) */
- Q_ASSERT_ID(520, nFree == (thr->super.eQueue.end + 1U));
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_GET_LAST, thr->super.prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(&thr->super); /* this active object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_END_NOCRIT_PRE_()
- }
- }
- else { /* the queue is still empty -- the timeout must have fired */
- e = (QEvt *)0;
- }
- QF_CRIT_X_();
- return e;</code>
- </operation>
- <!--${QXK::QXThread::init_}-->
- <operation name="init_" type="void" visibility="0x01" properties="0x01">
- <documentation>/*! Overrides QHsm_init_()
- * @private @memberof QXThread
- */
- /*! @private @memberof QXThread */</documentation>
- <!--${QXK::QXThread::init_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QXK::QXThread::init_::par}-->
- <parameter name="par" type="void const * const"/>
- <!--${QXK::QXThread::init_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>Q_UNUSED_PAR(me);
- Q_UNUSED_PAR(par);
- Q_UNUSED_PAR(qs_id);
- Q_ERROR_ID(110);</code>
- </operation>
- <!--${QXK::QXThread::dispatch_}-->
- <operation name="dispatch_" type="void" visibility="0x01" properties="0x01">
- <documentation>/*! Overrides QHsm_dispatch_()
- * @private @memberof QXThread
- */
- /*! @private @memberof QXThread */</documentation>
- <!--${QXK::QXThread::dispatch_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QXK::QXThread::dispatch_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QXK::QXThread::dispatch_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>Q_UNUSED_PAR(me);
- Q_UNUSED_PAR(e);
- Q_UNUSED_PAR(qs_id);
- Q_ERROR_ID(120);</code>
- </operation>
- <!--${QXK::QXThread::start_}-->
- <operation name="start_" type="void" visibility="0x01" properties="0x01">
- <documentation>/*! start QXThread private implementation
- * @private @memberof QXThread
- *
- * @details
- * Starts execution of an extended thread and registers it with the framework.
- * The extended thread becomes ready-to-run immediately and is scheduled
- * if the QXK is already running.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] prio QF-priority of the thread, but no preemption-
- * threshold. See also ::QPrioSpec.
- * @param[in] qSto pointer to the storage for the ring buffer of the
- * event queue. This cold be NULL, if this extended
- * thread does not use the built-in event queue.
- * @param[in] qLen length of the event queue [in events],
- * or zero if queue not used
- * @param[in] stkSto pointer to the stack storage (must be provided)
- * @param[in] stkSize stack size [in bytes] (must not be zero)
- * @param[in] par pointer to an extra parameter (might be NULL).
- *
- * @precondition{qxk_xthr,200}
- * - must NOT be called from an ISR;
- * - the stack storage must be provided;
- * - the thread must be instantiated (see QXThread_ctor())
- * - preemption-threshold is NOT provided (because QXK kernel
- * does not support preemption-threshold scheduling)
- *
- * @note
- * Currently, extended trheads in QXK do NOT support preemption-threshold.
- * The `prio` must NOT provide preemption-threshold and this function
- * will assert it in the precondition.
- *
- * @usage
- * QXThread_start_() should NOT be called directly, only via the macro
- * QXTHREAD_START(). The following example shows starting an extended
- * thread:
- * @include qxk_start.c
- */
- /*! @private @memberof QXThread */</documentation>
- <!--${QXK::QXThread::start_::me}-->
- <parameter name="me" type="QActive * const"/>
- <!--${QXK::QXThread::start_::prioSpec}-->
- <parameter name="prioSpec" type="QPrioSpec const"/>
- <!--${QXK::QXThread::start_::qSto}-->
- <parameter name="qSto" type="QEvt const * * const"/>
- <!--${QXK::QXThread::start_::qLen}-->
- <parameter name="qLen" type="uint_fast16_t const"/>
- <!--${QXK::QXThread::start_::stkSto}-->
- <parameter name="stkSto" type="void * const"/>
- <!--${QXK::QXThread::start_::stkSize}-->
- <parameter name="stkSize" type="uint_fast16_t const"/>
- <!--${QXK::QXThread::start_::par}-->
- <parameter name="par" type="void const * const"/>
- <code>Q_UNUSED_PAR(par);
- Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
- && (stkSto != (void *)0) /* stack must be provided */
- && (stkSize != 0U)
- && (me->super.state.act == (QActionHandler)0)
- && ((prioSpec & 0xFF00U) == 0U));
- /* is storage for the queue buffer provided? */
- if (qSto != (QEvt const **)0) {
- QEQueue_init(&me->eQueue, qSto, qLen);
- }
- /* extended thread constructor puts the thread handler in place of
- * the top-most initial transition 'me->super.temp.act'
- */
- QXK_stackInit_(me, me->super.temp.thr, stkSto, stkSize);
- /* the new thread is not blocked on any object */
- me->super.temp.obj = (QMState *)0;
- me->prio = (uint8_t)(prioSpec & 0xFFU); /* QF-priority of the AO */
- me->pthre = 0U; /* preemption-threshold NOT used */
- QActive_register_(me); /* make QF aware of this active object */
- QF_CRIT_STAT_
- QF_CRIT_E_();
- /* extended-thread becomes ready immediately */
- QPSet_insert(&QF_readySet_, (uint_fast8_t)me->prio);
- /* see if this thread needs to be scheduled in case QXK is running */
- if (QXK_attr_.lockCeil <= QF_MAX_ACTIVE) {
- (void)QXK_sched_(); /* schedule other threads */
- }
- QF_CRIT_X_();</code>
- </operation>
- <!--${QXK::QXThread::post_}-->
- <operation name="post_" type="bool" visibility="0x01" properties="0x01">
- <documentation>/*! post to the QXThread event queue private implementation
- * @private @memberof QXThread
- *
- * @details
- * Direct event posting is the simplest asynchronous communication method
- * available in QF. The following example illustrates how the Philo active
- * object posts directly the HUNGRY event to the Table active object.
- * <br>
- * The parameter `margin` specifies the minimum number of free slots in
- * the queue that must be available for posting to succeed. The function
- * returns 1 (success) if the posting succeeded (with the provided margin)
- * and 0 (failure) when the posting fails.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] e pointer to the event to be posted
- * @param[in] margin number of required free slots in the queue after
- * posting the event. The special value #QF_NO_MARGIN
- * means that this function will assert if posting fails.
- * @param[in] sender pointer to a sender object (used only for QS tracing).
- *
- * @returns
- * 'true' (success) if the posting succeeded (with the provided margin) and
- * 'false' (failure) when the posting fails.
- *
- * @note
- * Should be called only via the macro QXTHREAD_POST_X().
- *
- * @note
- * The #QF_NO_MARGIN value of the `margin` parameter is special and
- * denotes situation when the post() operation is assumed to succeed
- * (event delivery guarantee). An assertion fires, when the event cannot
- * be delivered in this case.
- *
- * @note
- * For compatibility with the V-table from the superclass ::QActive, the
- * me-pointer is typed as pointing to QActive. However, the `me` pointer
- * here actually points to the QXThread subclass. Therefore the downcast
- * (QXThread *)me is always correct.
- */
- /*! @private @memberof QXThread */</documentation>
- <!--${QXK::QXThread::post_::me}-->
- <parameter name="me" type="QActive * const"/>
- <!--${QXK::QXThread::post_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QXK::QXThread::post_::margin}-->
- <parameter name="margin" type="uint_fast16_t const"/>
- <!--${QXK::QXThread::post_::sender}-->
- <parameter name="sender" type="void const * const"/>
- <code>#ifndef Q_SPY
- Q_UNUSED_PAR(sender);
- #endif
- QF_CRIT_STAT_
- QS_TEST_PROBE_DEF(&QXThread_post_)
- /* is it the private time event? */
- bool status;
- if (e == &QXTHREAD_CAST_(me)->timeEvt.super) {
- QF_CRIT_E_();
- /* the private time event is disarmed and not in any queue,
- * so it is safe to change its signal. The signal of 0 means
- * that the time event has expired.
- */
- QXTHREAD_CAST_(me)->timeEvt.super.sig = 0U;
- QXThread_unblock_(QXTHREAD_CAST_(me));
- QF_CRIT_X_();
- status = true;
- }
- /* is the event queue provided? */
- else if (me->eQueue.end != 0U) {
- QEQueueCtr nFree;
- /*! @pre event pointer must be valid */
- Q_REQUIRE_ID(300, e != (QEvt *)0);
- QF_CRIT_E_();
- nFree = me->eQueue.nFree; /* get volatile into temporary */
- /* test-probe#1 for faking queue overflow */
- QS_TEST_PROBE_ID(1,
- nFree = 0U;
- )
- if (margin == QF_NO_MARGIN) {
- if (nFree > 0U) {
- status = true; /* can post */
- }
- else {
- status = false; /* cannot post */
- Q_ERROR_CRIT_(310); /* must be able to post the event */
- }
- }
- else if (nFree > (QEQueueCtr)margin) {
- status = true; /* can post */
- }
- else {
- status = false; /* cannot post, but don't assert */
- }
- /* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- QEvt_refCtr_inc_(e); /* increment the reference counter */
- }
- if (status) { /* can post the event? */
- --nFree; /* one free entry just used up */
- me->eQueue.nFree = nFree; /* update the original */
- if (me->eQueue.nMin > nFree) {
- me->eQueue.nMin = nFree; /* update minimum so far */
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(sender); /* the sender object */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this active object (recipient) */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* number of free entries */
- QS_EQC_PRE_(me->eQueue.nMin); /* min number of free entries */
- QS_END_NOCRIT_PRE_()
- /* queue empty? */
- if (me->eQueue.frontEvt == (QEvt *)0) {
- me->eQueue.frontEvt = e; /* deliver event directly */
- /* is this thread blocked on the queue? */
- if (me->super.temp.obj
- == QXK_PTR_CAST_(QMState*, &me->eQueue))
- {
- (void)QXThread_teDisarm_(QXTHREAD_CAST_(me));
- QPSet_insert(&QF_readySet_, (uint_fast8_t)me->prio);
- if (!QXK_ISR_CONTEXT_()) {
- (void)QXK_sched_(); /* schedule other threads */
- }
- }
- }
- /* queue is not empty, insert event into the ring-buffer */
- else {
- /* insert event into the ring buffer (FIFO) */
- me->eQueue.ring[me->eQueue.head] = e;
- /* need to wrap the head counter? */
- if (me->eQueue.head == 0U) {
- me->eQueue.head = me->eQueue.end; /* wrap around */
- }
- --me->eQueue.head; /* advance the head (counter clockwise) */
- }
- QF_CRIT_X_();
- }
- else { /* cannot post the event */
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_ATTEMPT, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(sender); /* the sender object */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this active object (recipient) */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & ref Count */
- QS_EQC_PRE_(nFree); /* number of free entries */
- QS_EQC_PRE_(margin); /* margin requested */
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_();
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e); /* recycle the event to avoid a leak */
- #endif
- }
- }
- else { /* the queue is not available */
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e); /* make sure the event is not leaked */
- #endif
- status = false;
- Q_ERROR_ID(320); /* this extended thread cannot accept events */
- }
- return status;</code>
- </operation>
- <!--${QXK::QXThread::postLIFO_}-->
- <operation name="postLIFO_" type="void" visibility="0x01" properties="0x01">
- <documentation>/*! post to the QXThread event queue (LIFO) private implementation
- * @private @memberof QXThread
- *
- * @details
- * Last-In-First-Out (LIFO) policy is not supported for extened threads.
- *
- * @param[in] me current instance pointer (see @ref oop)
- * @param[in] e pointer to the event to post to the queue
- *
- * @sa
- * QActive_postLIFO_()
- */
- /*! @private @memberof QXThread */</documentation>
- <!--${QXK::QXThread::postLIFO_::me}-->
- <parameter name="me" type="QActive * const"/>
- <!--${QXK::QXThread::postLIFO_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <code>Q_UNUSED_PAR(me);
- Q_UNUSED_PAR(e);
- Q_ERROR_ID(410);</code>
- </operation>
- <!--${QXK::QXThread::block_}-->
- <operation name="block_" type="void" visibility="0x02" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! block QXThread private implementation
- * @private @memberof QXThread
- *
- * @details
- * Internal implementation of blocking the given extended thread.
- *
- * @precondition{qxk_xthr,600}
- * - the thread holding the lock cannot block!
- *
- * @note
- * Must be called from within a critical section
- */
- /*! @private @memberof QXThread */</documentation>
- <code>Q_REQUIRE_ID(600, (QXK_attr_.lockHolder != me->super.prio));
- QPSet_remove(&QF_readySet_, (uint_fast8_t)me->super.prio);
- (void)QXK_sched_(); /* schedule other threads */</code>
- </operation>
- <!--${QXK::QXThread::unblock_}-->
- <operation name="unblock_" type="void" visibility="0x02" properties="0x00">
- <specifiers>const</specifiers>
- <documentation>/*! unblock QXThread private implementation
- * @private @memberof QXThread
- *
- * @details
- * Internal implementation of un-blocking the given extended thread.
- *
- * @note
- * must be called from within a critical section
- */
- /*! @private @memberof QXThread */</documentation>
- <code>QPSet_insert(&QF_readySet_, (uint_fast8_t)me->super.prio);
- if ((!QXK_ISR_CONTEXT_()) /* not inside ISR? */
- && (QActive_registry_[0] != (QActive *)0)) /* kernel started? */
- {
- (void)QXK_sched_(); /* schedule other threads */
- }</code>
- </operation>
- <!--${QXK::QXThread::teArm_}-->
- <operation name="teArm_" type="void" visibility="0x02" properties="0x00">
- <documentation>/*! arm internal time event private implementation
- * @private @memberof QXThread
- *
- * @details
- * Internal implementation of arming the private time event for a given
- * timeout at a given system tick rate.
- *
- * @precondition{qxk_xthr,700}
- * - the time event must be unused
- *
- * @note
- * Must be called from within a critical section
- */
- /*! @private @memberof QXThread */</documentation>
- <!--${QXK::QXThread::teArm_::sig}-->
- <parameter name="sig" type="enum_t const"/>
- <!--${QXK::QXThread::teArm_::nTicks}-->
- <parameter name="nTicks" type="uint_fast16_t const"/>
- <code>Q_REQUIRE_ID(700, me->timeEvt.ctr == 0U);
- me->timeEvt.super.sig = (QSignal)sig;
- if (nTicks != QXTHREAD_NO_TIMEOUT) {
- me->timeEvt.ctr = (QTimeEvtCtr)nTicks;
- me->timeEvt.interval = 0U;
- /* is the time event unlinked?
- * NOTE: For the duration of a single clock tick of the specified tick
- * rate a time event can be disarmed and yet still linked in the list,
- * because un-linking is performed exclusively in QTimeEvt_tick_().
- */
- if ((me->timeEvt.super.refCtr_ & QTE_IS_LINKED) == 0U) {
- uint_fast8_t const tickRate
- = ((uint_fast8_t)me->timeEvt.super.refCtr_ & QTE_TICK_RATE);
- Q_ASSERT_ID(710, tickRate < QF_MAX_TICK_RATE);
- me->timeEvt.super.refCtr_ |= QTE_IS_LINKED;
- /* The time event is initially inserted into the separate
- * "freshly armed" list based on QTimeEvt_timeEvtHead_[tickRate].act.
- * Only later, inside the QTimeEvt_tick_() function, the "freshly
- * armed" list is appended to the main list of armed time events
- * based on QTimeEvt_timeEvtHead_[tickRate].next. Again, this is
- * to keep any changes to the main list exclusively inside
- * QTimeEvt_tick_().
- */
- me->timeEvt.next
- = QXK_PTR_CAST_(QTimeEvt*, QTimeEvt_timeEvtHead_[tickRate].act);
- QTimeEvt_timeEvtHead_[tickRate].act = &me->timeEvt;
- }
- }</code>
- </operation>
- <!--${QXK::QXThread::teDisarm_}-->
- <operation name="teDisarm_" type="bool" visibility="0x02" properties="0x00">
- <documentation>/*! disarm internal time event private implementation
- * @private @memberof QXThread
- *
- * @details
- * Internal implementation of disarming the private time event.
- *
- * @note
- * Must be called from within a critical section
- */
- /*! @private @memberof QXThread */</documentation>
- <code>bool wasArmed;
- /* is the time evt running? */
- if (me->timeEvt.ctr != 0U) {
- wasArmed = true;
- me->timeEvt.ctr = 0U; /* schedule removal from list */
- }
- /* the time event was already automatically disarmed */
- else {
- wasArmed = false;
- }
- return wasArmed;</code>
- </operation>
- </class>
- <!--${QXK::QXThreadVtable}-->
- <attribute name="QXThreadVtable" type="typedef QActiveVtable" visibility="0x04" properties="0x00">
- <documentation>/*! @brief Virtual Table for the ::QXThread class
- * (inherited from ::QActiveVtable)
- *
- * @note
- * ::QXThread inherits ::QActive without adding any new virtual
- * functions and therefore, ::QXThreadVtable is typedef'ed as ::QActiveVtable.
- */</documentation>
- </attribute>
- <!--${QXK::QActive}-->
- <class name="QActive">
- <documentation>/*! QActive active object class customization for QK */</documentation>
- <!--${QXK::QActive::start_}-->
- <operation name="start_" type="void" visibility="0x00" properties="0x04">
- <documentation>/*! Starts execution of an active object and registers the object
- * with the framework customized for the QXK kernel
- * @public @memberof QActive
- *
- * @precondition{qxk,300}
- * - from an ISR;
- * - the stack storage must NOT be provided (because the QXK kernel
- * does not need per-AO stacks)
- * - preemption-threshold is NOT provided (because QXK kernel
- * does not support preemption-threshold scheduling)
- */
- /*! @public @memberof QActive */</documentation>
- <!--${QXK::QActive::start_::prioSpec}-->
- <parameter name="prioSpec" type="QPrioSpec const"/>
- <!--${QXK::QActive::start_::qSto}-->
- <parameter name="qSto" type="QEvt const * * const"/>
- <!--${QXK::QActive::start_::qLen}-->
- <parameter name="qLen" type="uint_fast16_t const"/>
- <!--${QXK::QActive::start_::stkSto}-->
- <parameter name="stkSto" type="void * const"/>
- <!--${QXK::QActive::start_::stkSize}-->
- <parameter name="stkSize" type="uint_fast16_t const"/>
- <!--${QXK::QActive::start_::par}-->
- <parameter name="par" type="void const * const"/>
- <code>Q_UNUSED_PAR(stkSto); /* not needed in QXK */
- Q_UNUSED_PAR(stkSize); /* not needed in QXK */
- Q_REQUIRE_ID(300, (!QXK_ISR_CONTEXT_())
- && (stkSto == (void *)0)
- && ((prioSpec & 0xFF00U) == 0U));
- me->prio = (uint8_t)(prioSpec & 0xFFU); /* QF-priority of the AO */
- me->pthre = 0U; /* preemption-threshold NOT used */
- QActive_register_(me); /* make QF aware of this active object */
- QEQueue_init(&me->eQueue, qSto, qLen); /* init the built-in queue */
- me->osObject = (void *)0; /* no private stack for the AO */
- QHSM_INIT(&me->super, par, me->prio); /* top-most initial tran. */
- QS_FLUSH(); /* flush the trace buffer to the host */
- /* see if this AO needs to be scheduled if QXK is already running */
- QF_CRIT_STAT_
- QF_CRIT_E_();
- if (QXK_attr_.lockCeil <= QF_MAX_ACTIVE) { /* scheduler running? */
- if (QXK_sched_() != 0U) { /* activation needed? */
- QXK_activate_(); /* synchronously activate basic-thred(s) */
- }
- }
- QF_CRIT_X_();</code>
- </operation>
- </class>
- <!--${QXK::QXSemaphore}-->
- <class name="QXSemaphore">
- <documentation>/*! @brief Counting Semaphore of the QXK preemptive kernel
- * @class QXSemaphore
- *
- * @details
- * ::QXSemaphore is a blocking mechanism intended primarily for signaling
- * @ref ::QXThread "extended threads". The semaphore is initialized with
- * the maximum count (see QXSemaphore_init()), which allows you to create
- * a binary semaphore (when the maximum count is 1) and
- * counting semaphore when the maximum count is > 1.
- *
- * @usage
- * The following example illustrates how to instantiate and use the semaphore
- * in your application.
- * @include qxk_sema.c
- */</documentation>
- <!--${QXK::QXSemaphore::waitSet}-->
- <attribute name="waitSet" type="QPSet" visibility="0x02" properties="0x00">
- <documentation>/*! set of extended threads waiting on this semaphore */</documentation>
- </attribute>
- <!--${QXK::QXSemaphore::count}-->
- <attribute name="count" type="uint8_t volatile" visibility="0x02" properties="0x00">
- <documentation>/*! semaphore up-down counter */</documentation>
- </attribute>
- <!--${QXK::QXSemaphore::max_count}-->
- <attribute name="max_count" type="uint8_t" visibility="0x02" properties="0x00">
- <documentation>/*! maximum value of the semaphore counter */</documentation>
- </attribute>
- <!--${QXK::QXSemaphore::init}-->
- <operation name="init" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! initialize the counting semaphore
- * @public @memberof QXSemaphore
- *
- * @details
- * Initializes a semaphore with the specified count and maximum count.
- * If the semaphore is used for resource sharing, both the initial count
- * and maximum count should be set to the number of identical resources
- * guarded by the semaphore. If the semaphore is used as a signaling
- * mechanism, the initial count should set to 0 and maximum count to 1
- * (binary semaphore).
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] count initial value of the semaphore counter
- * @param[in] max_count maximum value of the semaphore counter.
- * The purpose of the max_count is to limit the counter
- * so that the semaphore cannot unblock more times than
- * the maximum.
- *
- * @precondition{qxk_sema,100}
- * - max_count must be greater than zero
- *
- * @note
- * QXSemaphore_init() must be called **before** the semaphore can be used
- * (signaled or waited on).
- */
- /*! @public @memberof QXSemaphore */</documentation>
- <!--${QXK::QXSemaphore::init::count}-->
- <parameter name="count" type="uint_fast8_t const"/>
- <!--${QXK::QXSemaphore::init::max_count}-->
- <parameter name="max_count" type="uint_fast8_t const"/>
- <code>Q_REQUIRE_ID(100, max_count > 0U);
- me->count = (uint8_t)count;
- me->max_count = (uint8_t)max_count;
- QPSet_setEmpty(&me->waitSet);</code>
- </operation>
- <!--${QXK::QXSemaphore::wait}-->
- <operation name="wait" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! wait (block) on the semaphore
- * @public @memberof QXSemaphore
- *
- * @details
- * When an extended thread calls QXSemaphore_wait() and the value of the
- * semaphore counter is greater than 0, QXSemaphore_wait() decrements the
- * semaphore counter and returns (true) to its caller. However, if the value
- * of the semaphore counter is 0, the function places the calling thread in
- * the waiting list for the semaphore. The thread waits until the semaphore
- * is signaled by calling QXSemaphore_signal(), or the specified timeout
- * expires. If the semaphore is signaled before the timeout expires, QXK
- * resumes the highest-priority extended thread waiting for the semaphore.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] nTicks number of clock ticks (at the associated rate)
- * to wait for the semaphore. The value of
- * ::QXTHREAD_NO_TIMEOUT indicates that no timeout will
- * occur and the semaphore will wait indefinitely.
- * @returns
- * 'true' if the semaphore has been signaled and 'false' if a timeout
- * occurred.
- *
- * @precondition{qxk_sema,200}
- * - must NOT be called from an ISR;
- * - the semaphore must be initialized
- * - be called from an extended thread;
- * - the thread must NOT be already blocked on any object.
- *
- * @precondition{qxk_sema,201}
- * - the thread must NOT be holding a scheduler lock.
- *
- * @note
- * Multiple extended threads can wait for a given semaphore.
- */
- /*! @public @memberof QXSemaphore */</documentation>
- <!--${QXK::QXSemaphore::wait::nTicks}-->
- <parameter name="nTicks" type="uint_fast16_t const"/>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QXThread * const curr = QXK_PTR_CAST_(QXThread*, QXK_attr_.curr);
- Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) /* can't wait inside an ISR */
- && (me->max_count > 0U) /* sema must be initialized */
- && (curr != (QXThread *)0) /* curr must be extended */
- && (curr->super.super.temp.obj == (QMState *)0)); /* NOT blocked */
- Q_REQUIRE_ID(201, QXK_attr_.lockHolder != curr->super.prio);
- bool signaled = true; /* assume that the semaphore will be signaled */
- if (me->count > 0U) {
- --me->count; /* semaphore taken: decrement the count */
- QS_BEGIN_NOCRIT_PRE_(QS_SEM_TAKE, curr->super.prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this semaphore */
- QS_2U8_PRE_(curr->super.prio,
- me->count);
- QS_END_NOCRIT_PRE_()
- }
- else {
- uint_fast8_t const p = (uint_fast8_t)curr->super.prio;
- /* remove the curr prio from the ready set (will block)
- * and insert to the waiting set on this semaphore
- */
- QPSet_remove(&QF_readySet_, p);
- QPSet_insert(&me->waitSet, p);
- /* remember the blocking object (this semaphore) */
- curr->super.super.temp.obj = QXK_PTR_CAST_(QMState*, me);
- QXThread_teArm_(curr, (enum_t)QXK_TIMEOUT_SIG, nTicks);
- QS_BEGIN_NOCRIT_PRE_(QS_SEM_BLOCK, curr->super.prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this semaphore */
- QS_2U8_PRE_(curr->super.prio,
- me->count);
- QS_END_NOCRIT_PRE_()
- /* schedule the next thread if multitasking started */
- (void)QXK_sched_(); /* schedule other theads */
- QF_CRIT_X_();
- QF_CRIT_EXIT_NOP(); /* BLOCK here !!! */
- QF_CRIT_E_(); /* AFTER unblocking... */
- /* the blocking object must be this semaphore */
- Q_ASSERT_ID(240, curr->super.super.temp.obj
- == QXK_PTR_CAST_(QMState*, me));
- /* did the blocking time-out? (signal of zero means that it did) */
- if (curr->timeEvt.super.sig == 0U) {
- if (QPSet_hasElement(&me->waitSet, p)) { /* still waiting? */
- QPSet_remove(&me->waitSet, p); /* remove unblocked thread */
- signaled = false; /* the semaphore was NOT signaled */
- /* semaphore NOT taken: do NOT decrement the count */
- }
- else { /* semaphore was both signaled and timed out */
- --me->count; /* semaphore taken: decrement the count */
- }
- }
- else { /* blocking did NOT time out */
- /* the thread must NOT be waiting on this semaphore */
- Q_ASSERT_ID(250,!QPSet_hasElement(&me->waitSet, p));
- --me->count; /* semaphore taken: decrement the count */
- }
- curr->super.super.temp.obj = (QMState *)0; /* clear blocking obj. */
- }
- QF_CRIT_X_();
- return signaled;</code>
- </operation>
- <!--${QXK::QXSemaphore::tryWait}-->
- <operation name="tryWait" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! try wait on the semaphore (non-blocking)
- * @public @memberof QXSemaphore
- *
- * @details
- * This function checks if the semaphore counter is greater than 0,
- * in which case the counter is decremented.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @returns
- * 'true' if the semaphore has count available and 'false' NOT available.
- *
- * @precondition{qxk_sema,300}
- * - the semaphore must be initialized
- *
- * @note
- * This function can be called from any context, including ISRs and basic
- * threads (active objects).
- */
- /*! @public @memberof QXSemaphore */</documentation>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- Q_REQUIRE_ID(300, me->max_count > 0U);
- #ifdef Q_SPY
- QActive const * const curr = QXK_PTR_CAST_(QActive*, QXK_attr_.curr);
- #endif /* Q_SPY */
- bool isAvailable;
- /* is the semaphore available? */
- if (me->count > 0U) {
- --me->count;
- isAvailable = true;
- QS_BEGIN_NOCRIT_PRE_(QS_SEM_TAKE, curr->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this semaphore */
- QS_2U8_PRE_(curr->prio,
- me->count);
- QS_END_NOCRIT_PRE_()
- }
- else { /* the semaphore is NOT available (would block) */
- isAvailable = false;
- QS_BEGIN_NOCRIT_PRE_(QS_SEM_BLOCK_ATTEMPT, curr->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this semaphore */
- QS_2U8_PRE_(curr->prio,
- me->count);
- QS_END_NOCRIT_PRE_()
- }
- QF_CRIT_X_();
- return isAvailable;</code>
- </operation>
- <!--${QXK::QXSemaphore::signal}-->
- <operation name="signal" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! signal (unblock) the semaphore
- * @public @memberof QXSemaphore
- *
- * @details
- * If the semaphore counter value is 0 or more, it is incremented, and
- * this function returns to its caller. If the extended threads are waiting
- * for the semaphore to be signaled, QXSemaphore_signal() removes the highest-
- * priority thread waiting for the semaphore from the waiting list and makes
- * this thread ready-to-run. The QXK scheduler is then called to determine if
- * the awakened thread is now the highest-priority thread that is ready-to-run.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @returns
- * 'true' when the semaphore signaled and 'false' when the semaphore count
- * exceeded the maximum.
- *
- * @precondition{qxk_sema,400}
- * - the semaphore must be initialized
- *
- * @note
- * A semaphore can be signaled from many places, including from ISRs, basic
- * threads (AOs), and extended threads.
- */
- /*! @public @memberof QXSemaphore */</documentation>
- <code>Q_REQUIRE_ID(400, me->max_count > 0U);
- QF_CRIT_STAT_
- QF_CRIT_E_();
- bool signaled = true; /* assume that the semaphore will be signaled */
- if (me->count < me->max_count) {
- ++me->count; /* increment the semaphore count */
- #ifdef Q_SPY
- QActive const * const curr = QXK_PTR_CAST_(QActive*, QXK_attr_.curr);
- #endif /* Q_SPY */
- QS_BEGIN_NOCRIT_PRE_(QS_SEM_SIGNAL, curr->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this semaphore */
- QS_2U8_PRE_(curr->prio,
- me->count);
- QS_END_NOCRIT_PRE_()
- if (QPSet_notEmpty(&me->waitSet)) {
- /* find the highest-priority thread waiting on this semaphore */
- uint_fast8_t const p = QPSet_findMax(&me->waitSet);
- QXThread * const thr =
- QXK_PTR_CAST_(QXThread*, QActive_registry_[p]);
- /* assert that the tread:
- * - must be registered in QF;
- * - must be extended; and
- * - must be blocked on this semaphore;
- */
- Q_ASSERT_ID(410, (thr != (QXThread *)0)
- && (thr->super.osObject != (struct QActive *)0)
- && (thr->super.super.temp.obj
- == QXK_PTR_CAST_(QMState*, me)));
- /* disarm the internal time event */
- (void)QXThread_teDisarm_(thr);
- /* make the thread ready to run and remove from the wait-list */
- QPSet_insert(&QF_readySet_, p);
- QPSet_remove(&me->waitSet, p);
- QS_BEGIN_NOCRIT_PRE_(QS_SEM_TAKE, thr->super.prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this semaphore */
- QS_2U8_PRE_(thr->super.prio,
- me->count);
- QS_END_NOCRIT_PRE_()
- if (!QXK_ISR_CONTEXT_()) { /* not inside ISR? */
- (void)QXK_sched_(); /* schedule other threads */
- }
- }
- }
- else {
- signaled = false; /* semaphore NOT signaled */
- }
- QF_CRIT_X_();
- return signaled;</code>
- </operation>
- </class>
- <!--${QXK::QXMutex}-->
- <class name="QXMutex">
- <documentation>/*! @brief Blocking Mutex the QXK preemptive kernel
- * @class QXMutex
- *
- * @details
- * ::QXMutex is a blocking mutual exclusion mechanism that can also apply
- * the **priority-ceiling protocol** to avoid unbounded priority inversion
- * (if initialized with a non-zero ceiling priority, see QXMutex_init()).
- * In that case, ::QXMutex requires its own uinque QP priority level, which
- * cannot be used by any thread or any other ::QXMutex.
- * If initialized with preemption-ceiling of zero, ::QXMutex does **not**
- * use the priority-ceiling protocol and does not require a unique QP
- * priority (see QXMutex_init()).
- * ::QXMutex is **recursive** (re-entrant), which means that it can be locked
- * multiple times (up to 255 levels) by the *same* thread without causing
- * deadlock.
- * ::QXMutex is primarily intended for the @ref ::QXThread
- * "extened (blocking) threads", but can also be used by the @ref ::QActive
- * "basic threads" through the non-blocking QXMutex_tryLock() API.
- *
- * @note
- * ::QXMutex should be used in situations when at least one of the extended
- * threads contending for the mutex blocks while holding the mutex (between
- * the QXMutex_lock() and QXMutex_unlock() operations). If no blocking is
- * needed while holding the mutex, the more efficient non-blocking mechanism
- * of @ref srs_qxk_schedLock() "selective QXK scheduler locking" should be used
- * instead. @ref srs_qxk_schedLock() "Selective scheduler locking" is available
- * for both @ref ::QActive "basic threads" and @ref ::QXThread "extended
- * threads", so it is applicable to situations where resources are shared
- * among all these threads.
- *
- * @usage
- * The following example illustrates how to instantiate and use the mutex
- * in your application.
- * @include qxk_mutex.c
- */</documentation>
- <!--${QXK::QXMutex::ao}-->
- <attribute name="ao" type="QActive" visibility="0x02" properties="0x00">
- <documentation>/*! active object used as a placeholder AO for this mutex
- * in QActive_registry_[]
- */</documentation>
- </attribute>
- <!--${QXK::QXMutex::waitSet}-->
- <attribute name="waitSet" type="QPSet" visibility="0x02" properties="0x00">
- <documentation>/*! set of extended-threads waiting on this mutex */</documentation>
- </attribute>
- <!--${QXK::QXMutex::init}-->
- <operation name="init" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! initialize the QXK priority-ceiling mutex ::QXMutex
- * @public @memberof QXMutex
- *
- * @details
- * Initialize the QXK priority ceiling mutex.
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] prioSpec the priority specification for the mutex
- * (See also ::QPrioSpec). This value might
- * also be zero.
- *
- * @precondition{qxk_mutex,100}
- * - preemption-threshold must not be used
- *
- * @note
- * `prioSpec == 0` means that the priority-ceiling protocol shall **not**
- * be used by this mutex. Such mutex will **not** change (boost) the
- * priority of the holding threads.<br>
- *
- * Conversely, `prioSpec != 0` means that the priority-ceiling protocol
- * shall be used by this mutex. Such mutex **will** temporarily boost
- * the priority and priority-threshold of the holding thread to the
- * priority specification in `prioSpec` (see ::QPrioSpec).
- *
- * @usage
- * @include qxk_mutex.c
- */
- /*! @public @memberof QXMutex */</documentation>
- <!--${QXK::QXMutex::init::prioSpec}-->
- <parameter name="prioSpec" type="QPrioSpec const"/>
- <code>Q_REQUIRE_ID(100, (prioSpec & 0xFF00U) == 0U);
- me->ao.prio = (uint8_t)(prioSpec & 0xFFU); /* QF-priority */
- me->ao.pthre = 0U; /* preemption-threshold (not used) */
- if (prioSpec != 0U) { /* priority-ceiling protocol used? */
- QActive_register_(&me->ao); /* register this mutex as AO */
- }</code>
- </operation>
- <!--${QXK::QXMutex::lock}-->
- <operation name="lock" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! lock the QXK priority-ceiling mutex ::QXMutex
- * @public @memberof QXMutex
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- * @param[in] nTicks number of clock ticks (at the associated rate)
- * to wait for the mutex. The value of
- * ::QXTHREAD_NO_TIMEOUT indicates that no timeout will
- * occur and the mutex could block indefinitely.
- * @returns
- * 'true' if the mutex has been acquired and 'false' if a timeout occurred.
- *
- * @precondition{qxk_mutex,200}
- * - must NOT be called from an ISR;
- * - must be called from an extended thread;
- * - the mutex-priority must be in range;
- * - the thread must NOT be already blocked on any object.
- *
- * @note
- * The mutex locks are allowed to nest, meaning that the same extended thread
- * can lock the same mutex multiple times (< 255). However, each call to
- * QXMutex_lock() must be balanced by the matching call to QXMutex_unlock().
- *
- * @usage
- * @include qxk_mutex.c
- */
- /*! @public @memberof QXMutex */</documentation>
- <!--${QXK::QXMutex::lock::nTicks}-->
- <parameter name="nTicks" type="uint_fast16_t const"/>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QXThread * const curr = QXK_PTR_CAST_(QXThread*, QXK_attr_.curr);
- Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
- && (curr != (QXThread *)0) /* current thread must be extended */
- && (me->ao.prio <= QF_MAX_ACTIVE)
- && (curr->super.super.temp.obj == (QMState *)0)); /* not blocked */
- /*! @pre also: the thread must NOT be holding a scheduler lock. */
- Q_REQUIRE_ID(201, QXK_attr_.lockHolder != curr->super.prio);
- /* is the mutex available? */
- bool locked = true; /* assume that the mutex will be locked */
- if (me->ao.eQueue.nFree == 0U) {
- me->ao.eQueue.nFree = 1U; /* mutex lock nesting */
- /*! @pre also: the newly locked mutex must have no holder yet */
- Q_REQUIRE_ID(202, me->ao.thread == (void *)0);
- /* set the new mutex holder to the curr thread and
- * save the thread's prio in the mutex
- * NOTE: reuse the otherwise unused eQueue data member.
- */
- me->ao.thread = curr;
- me->ao.eQueue.head = (QEQueueCtr)curr->super.prio;
- QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, curr->super.prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this mutex */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.head); /* holder prio */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); /* nesting */
- QS_END_NOCRIT_PRE_()
- if (me->ao.prio != 0U) { /* priority-ceiling protocol used? */
- /* the holder priority must be lower than that of the mutex
- * and the priority slot must be occupied by this mutex
- */
- Q_ASSERT_ID(210, (curr->super.prio < me->ao.prio)
- && (QActive_registry_[me->ao.prio] == &me->ao));
- /* remove the thread's original prio from the ready set
- * and insert the mutex's prio into the ready set
- */
- QPSet_remove(&QF_readySet_, (uint_fast8_t)me->ao.eQueue.head);
- QPSet_insert(&QF_readySet_, (uint_fast8_t)me->ao.prio);
- /* put the thread into the AO registry in place of the mutex */
- QActive_registry_[me->ao.prio] = &curr->super;
- /* set thread's prio to that of the mutex */
- curr->super.prio = me->ao.prio;
- }
- }
- /* is the mutex locked by this thread already (nested locking)? */
- else if (me->ao.thread == &curr->super) {
- /* the nesting level beyond the arbitrary but high limit
- * most likely means cyclic or recursive locking of a mutex.
- */
- Q_ASSERT_ID(220, me->ao.eQueue.nFree < 0xFFU);
- ++me->ao.eQueue.nFree; /* lock one more level */
- QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, curr->super.prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this mutex */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.head); /* holder prio */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); /* nesting */
- QS_END_NOCRIT_PRE_()
- }
- else { /* the mutex is already locked by a different thread */
- /* the mutex holder must be valid */
- Q_ASSERT_ID(230, me->ao.thread != (void *)0);
- if (me->ao.prio != 0U) { /* priority-ceiling protocol used? */
- /* the prio slot must be occupied by the thr. holding the mutex */
- Q_ASSERT_ID(240, QActive_registry_[me->ao.prio]
- == QXK_PTR_CAST_(QActive *, me->ao.thread));
- }
- /* remove the curr thread's prio from the ready set (will block)
- * and insert it to the waiting set on this mutex
- */
- uint_fast8_t const p = (uint_fast8_t)curr->super.prio;
- QPSet_remove(&QF_readySet_, p);
- QPSet_insert(&me->waitSet, p);
- /* set the blocking object (this mutex) */
- curr->super.super.temp.obj = QXK_PTR_CAST_(QMState*, me);
- QXThread_teArm_(curr, (enum_t)QXK_TIMEOUT_SIG, nTicks);
- QS_BEGIN_NOCRIT_PRE_(QS_MTX_BLOCK, curr->super.prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this mutex */
- QS_2U8_PRE_((uint8_t)me->ao.eQueue.head, /* holder prio */
- curr->super.prio); /* blocked thread prio */
- QS_END_NOCRIT_PRE_()
- /* schedule the next thread if multitasking started */
- (void)QXK_sched_(); /* schedule other threads */
- QF_CRIT_X_();
- QF_CRIT_EXIT_NOP(); /* BLOCK here !!! */
- /* AFTER unblocking... */
- QF_CRIT_E_();
- /* the blocking object must be this mutex */
- Q_ASSERT_ID(240, curr->super.super.temp.obj
- == QXK_PTR_CAST_(QMState*, me));
- /* did the blocking time-out? (signal of zero means that it did) */
- if (curr->timeEvt.super.sig == 0U) {
- if (QPSet_hasElement(&me->waitSet, p)) { /* still waiting? */
- QPSet_remove(&me->waitSet, p); /* remove unblocked thread */
- locked = false; /* the mutex was NOT locked */
- }
- }
- else { /* blocking did NOT time out */
- /* the thread must NOT be waiting on this mutex */
- Q_ASSERT_ID(250, !QPSet_hasElement(&me->waitSet, p));
- }
- curr->super.super.temp.obj = (QMState *)0; /* clear blocking obj. */
- }
- QF_CRIT_X_();
- return locked;</code>
- </operation>
- <!--${QXK::QXMutex::tryLock}-->
- <operation name="tryLock" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! try to lock the QXK priority-ceiling mutex ::QXMutex
- * @public @memberof QXMutex
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @returns
- * 'true' if the mutex was successfully locked and 'false' if the mutex was
- * unavailable and was NOT locked.
- *
- * @precondition{qxk_mutex,300}
- * - must NOT be called from an ISR;
- * - the calling thread must be valid;
- * - the mutex-priority must be in range
- *
- * @precondition{qxk_mutex,301}
- * - the thread must NOT be holding a scheduler lock.
- *
- * @note
- * This function **can** be called from both basic threads (active objects)
- * and extended threads.
- *
- * @note
- * The mutex locks are allowed to nest, meaning that the same extended thread
- * can lock the same mutex multiple times (<= 255). However, each successful
- * call to QXMutex_tryLock() must be balanced by the matching call to
- * QXMutex_unlock().
- */
- /*! @public @memberof QXMutex */</documentation>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QActive *curr = QXK_attr_.curr;
- if (curr == (QActive *)0) { /* called from a basic thread? */
- curr = QActive_registry_[QXK_attr_.actPrio];
- }
- Q_REQUIRE_ID(300, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
- && (curr != (QActive *)0) /* current thread must be valid */
- && (me->ao.prio <= QF_MAX_ACTIVE));
- Q_REQUIRE_ID(301, QXK_attr_.lockHolder != curr->prio);
- /* is the mutex available? */
- if (me->ao.eQueue.nFree == 0U) {
- me->ao.eQueue.nFree = 1U; /* mutex lock nesting */
- /*! @pre also: the newly locked mutex must have no holder yet */
- Q_REQUIRE_ID(302, me->ao.thread == (void *)0);
- /* set the new mutex holder to the curr thread and
- * save the thread's prio in the mutex
- * NOTE: reuse the otherwise unused eQueue data member.
- */
- me->ao.thread = curr;
- me->ao.eQueue.head = (QEQueueCtr)curr->prio;
- QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, curr->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this mutex */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.head); /* holder prio */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); /* nesting */
- QS_END_NOCRIT_PRE_()
- if (me->ao.prio != 0U) { /* priority-ceiling protocol used? */
- /* the holder priority must be lower than that of the mutex
- * and the priority slot must be occupied by this mutex
- */
- Q_ASSERT_ID(210, (curr->prio < me->ao.prio)
- && (QActive_registry_[me->ao.prio] == &me->ao));
- /* remove the thread's original prio from the ready set
- * and insert the mutex's prio into the ready set
- */
- QPSet_remove(&QF_readySet_, (uint_fast8_t)me->ao.eQueue.head);
- QPSet_insert(&QF_readySet_, (uint_fast8_t)me->ao.prio);
- /* put the thread into the AO registry in place of the mutex */
- QActive_registry_[me->ao.prio] = curr;
- /* set thread's prio to that of the mutex */
- curr->prio = me->ao.prio;
- }
- }
- /* is the mutex locked by this thread already (nested locking)? */
- else if (me->ao.thread == curr) {
- /* the nesting level must not exceed the specified limit */
- Q_ASSERT_ID(320, me->ao.eQueue.nFree < 0xFFU);
- ++me->ao.eQueue.nFree; /* lock one more level */
- QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, curr->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this mutex */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.head); /* holder prio */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); /* nesting */
- QS_END_NOCRIT_PRE_()
- }
- else { /* the mutex is already locked by a different thread */
- if (me->ao.prio != 0U) { /* priority-ceiling protocol used? */
- /* the prio slot must be occupied by the thr. holding the mutex */
- Q_ASSERT_ID(340, QActive_registry_[me->ao.prio]
- == QXK_PTR_CAST_(QActive *, me->ao.thread));
- }
- QS_BEGIN_NOCRIT_PRE_(QS_MTX_BLOCK_ATTEMPT, curr->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this mutex */
- QS_2U8_PRE_((uint8_t)me->ao.eQueue.head, /* holder prio */
- curr->prio); /* trying thread prio */
- QS_END_NOCRIT_PRE_()
- curr = (QActive *)0; /* means that mutex is NOT available */
- }
- QF_CRIT_X_();
- return curr != (QActive *)0;</code>
- </operation>
- <!--${QXK::QXMutex::unlock}-->
- <operation name="unlock" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! unlock the QXK priority-ceiling mutex ::QXMutex
- * @public @memberof QXMutex
- *
- * @param[in,out] me current instance pointer (see @ref oop)
- *
- * @precondition{qxk_mutex,400}
- * - must NOT be called from an ISR;
- * - the calling thread must be valid;
- *
- * @precondition{qxk_mutex,401}
- * - the mutex must be already locked at least once.
- *
- * @precondition{qxk_mutex,402}
- * - the mutex must be held by this thread.
- *
- * @note
- * This function **can** be called from both basic threads (active objects)
- * and extended threads.
- *
- * @note
- * The mutex locks are allowed to nest, meaning that the same extended thread
- * can lock the same mutex multiple times (<= 225). However, each call to
- * QXMutex_lock() or a *successful* call to QXMutex_tryLock() must be
- * balanced by the matching call to QXMutex_unlock().
- *
- * @usage
- * @include qxk_mutex.c
- */
- /*! @public @memberof QXMutex */</documentation>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QActive *curr = QXK_attr_.curr;
- if (curr == (QActive *)0) { /* called from a basic thread? */
- curr = QActive_registry_[QXK_attr_.actPrio];
- }
- Q_REQUIRE_ID(400, (!QXK_ISR_CONTEXT_()) /* don't call from an ISR! */
- && (curr != (QActive *)0)); /* current thread must be valid */
- Q_REQUIRE_ID(401, me->ao.eQueue.nFree > 0U);
- Q_REQUIRE_ID(402, me->ao.thread == curr);
- /* is this the last nesting level? */
- if (me->ao.eQueue.nFree == 1U) {
- if (me->ao.prio != 0U) { /* priority-ceiling protocol used? */
- /* restore the holding thread's prio from the mutex */
- curr->prio = (uint8_t)me->ao.eQueue.head;
- /* put the mutex back into the AO registry */
- QActive_registry_[me->ao.prio] = &me->ao;
- /* remove the mutex' prio from the ready set
- * and insert the original thread's priority
- */
- QPSet_remove(&QF_readySet_, (uint_fast8_t)me->ao.prio);
- QPSet_insert(&QF_readySet_, (uint_fast8_t)me->ao.eQueue.head);
- }
- QS_BEGIN_NOCRIT_PRE_(QS_MTX_UNLOCK, curr->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this mutex */
- QS_2U8_PRE_((uint8_t)me->ao.eQueue.head, /* holder prio */
- 0U); /* nesting */
- QS_END_NOCRIT_PRE_()
- /* are any other threads waiting on this mutex? */
- if (QPSet_notEmpty(&me->waitSet)) {
- /* find the highest-priority thread waiting on this mutex */
- uint_fast8_t const p = QPSet_findMax(&me->waitSet);
- /* remove this thread from waiting on the mutex
- * and insert it into the ready set.
- */
- QPSet_remove(&me->waitSet, p);
- QPSet_insert(&QF_readySet_, p);
- QXThread * const thr =
- QXK_PTR_CAST_(QXThread*, QActive_registry_[p]);
- /* the waiting thread must:
- * - be registered in QF
- * - have the priority corresponding to the registration
- * - be an extended thread
- * - be blocked on this mutex
- */
- Q_ASSERT_ID(410, (thr != (QXThread *)0)
- && (thr->super.prio == (uint8_t)p)
- && (thr->super.super.state.act == Q_ACTION_CAST(0))
- && (thr->super.super.temp.obj
- == QXK_PTR_CAST_(QMState*, me)));
- /* disarm the internal time event */
- (void)QXThread_teDisarm_(thr);
- /* set the new mutex holder to the curr thread and
- * save the thread's prio in the mutex
- * NOTE: reuse the otherwise unused eQueue data member.
- */
- me->ao.thread = thr;
- me->ao.eQueue.head = (QEQueueCtr)thr->super.prio;
- QS_BEGIN_NOCRIT_PRE_(QS_MTX_LOCK, thr->super.prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this mutex */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.head); /* holder prio */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); /* nesting */
- QS_END_NOCRIT_PRE_()
- if (me->ao.prio != 0U) { /* priority-ceiling protocol used? */
- /* the holder priority must be lower than that of the mutex */
- Q_ASSERT_ID(410, thr->super.prio < me->ao.prio);
- /* put the thread into AO registry in place of the mutex */
- QActive_registry_[me->ao.prio] = &thr->super;
- }
- }
- else { /* no threads are waiting for this mutex */
- me->ao.eQueue.nFree = 0U; /* free up the nesting count */
- /* the mutex no longer held by any thread */
- me->ao.thread = (void *)0;
- me->ao.eQueue.head = 0U;
- if (me->ao.prio != 0U) { /* priority-ceiling protocol used? */
- /* put the mutex back at the original mutex slot */
- QActive_registry_[me->ao.prio] =
- QXK_PTR_CAST_(QActive*, me);
- }
- }
- /* schedule the next thread if multitasking started */
- if (QXK_sched_() != 0U) { /* activation needed? */
- QXK_activate_(); /* synchronously activate basic-thred(s) */
- }
- }
- else { /* releasing one level of nested mutex lock */
- Q_ASSERT_ID(420, me->ao.eQueue.nFree > 0U);
- --me->ao.eQueue.nFree; /* unlock one level */
- QS_BEGIN_NOCRIT_PRE_(QS_MTX_UNLOCK_ATTEMPT, curr->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(me); /* this mutex */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.head); /* holder prio */
- QS_U8_PRE_((uint8_t)me->ao.eQueue.nFree); /* nesting */
- QS_END_NOCRIT_PRE_()
- }
- QF_CRIT_X_();</code>
- </operation>
- </class>
- <!--${QXK::QXK-extern-C}-->
- <package name="QXK-extern-C" stereotype="0x02" namespace="QXK_">
- <!--${QXK::QXK-extern-C::Attr}-->
- <attribute name="Attr" type="typedef struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief The QXK kernel class
- * @class QXK
- *
- * @note
- * The order and alignment of the data members in this struct might
- * be important in QXK ports, where the members might be accessed
- * in assembly.
- */</documentation>
- <code>{
- struct QActive * volatile curr; /*!< current thread (NULL=basic) */
- struct QActive * volatile next; /*!< next thread to run */
- struct QActive * volatile prev; /*!< previous thread */
- uint8_t volatile actPrio; /*!< QF-prio of the active AO */
- uint8_t volatile lockCeil; /*!< lock-ceiling (0==no-lock) */
- uint8_t volatile lockHolder; /*!< prio of the lock holder */
- } QXK;</code>
- </attribute>
- <!--${QXK::QXK-extern-C::attr_}-->
- <attribute name="attr_" type="QXK" visibility="0x01" properties="0x00">
- <documentation>/*! attributes of the QXK kernel
- * @static @private @memberof QXK
- */
- /*! @static @private @memberof QXK */</documentation>
- </attribute>
- <!--${QXK::QXK-extern-C::sched_}-->
- <operation name="sched_" type="uint_fast8_t" visibility="0x00" properties="0x00">
- <documentation>/*! QXK scheduler finds the highest-priority thread ready to run
- * @static @private @memberof QXK
- *
- * @details
- * The QXK scheduler finds the priority of the highest-priority thread
- * that is ready to run.
- *
- * @returns
- * the 1-based priority of the the thread (basic or extended) run next,
- * or zero if no eligible thread is found.
- *
- * @attention
- * QXK_sched_() must be always called with interrupts **disabled** and
- * returns with interrupts **disabled**.
- */
- /*! @static @private @memberof QXK */</documentation>
- <code>uint_fast8_t p;
- if (QPSet_isEmpty(&QF_readySet_)) {
- p = 0U; /* no activation needed */
- }
- else {
- /* find the highest-prio thread ready to run */
- p = QPSet_findMax(&QF_readySet_);
- if (p <= QXK_attr_.lockCeil) {
- /* priority of the thread holding the lock */
- p = (uint_fast8_t)QActive_registry_[QXK_attr_.lockHolder]->prio;
- if (p != 0U) {
- Q_ASSERT_ID(610, QPSet_hasElement(&QF_readySet_, p));
- }
- }
- }
- QActive const * const curr = QXK_attr_.curr;
- QActive * const next = QActive_registry_[p];
- /* the next thread found must be registered in QF */
- Q_ASSERT_ID(620, next != (QActive *)0);
- /* is the current thread a basic-thread? */
- if (curr == (QActive *)0) {
- /* is the new priority above the active priority? */
- if (p > QXK_attr_.actPrio) {
- QXK_attr_.next = next; /* set the next AO to activate */
- if (next->osObject != (void *)0) { /* is next extended? */
- QXK_CONTEXT_SWITCH_();
- p = 0U; /* no activation needed */
- }
- }
- else { /* below the pre-thre */
- QXK_attr_.next = (QActive *)0;
- p = 0U; /* no activation needed */
- }
- }
- else { /* currently executing an extended-thread */
- /* is the current thread different from the next? */
- if (curr != next) {
- QXK_attr_.next = next;
- QXK_CONTEXT_SWITCH_();
- }
- else { /* current is the same as next */
- QXK_attr_.next = (QActive *)0; /* no need to context-switch */
- }
- p = 0U; /* no activation needed */
- }
- return p;</code>
- </operation>
- <!--${QXK::QXK-extern-C::activate_}-->
- <operation name="activate_" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! QXK activator activates the next active object. The activated AO
- * preempts the currently executing AOs.
- * @static @private @memberof QXK
- *
- * @details
- * QXK_activate_() activates ready-to run AOs that are above the initial
- * active priority (QXK_attr_.actPrio).
- *
- * @precondition{qxk,700}
- * - QXK_attr_.next must be valid and the prio must be in range
- *
- * @attention
- * QXK_activate_() must be always called with interrupts **disabled** and
- * returns with interrupts **disabled**.
- */
- /*! @static @private @memberof QXK */</documentation>
- <code>uint8_t const prio_in = QXK_attr_.actPrio;
- QActive *next = QXK_attr_.next; /* the next AO (basic-thread) to run */
- Q_REQUIRE_ID(700, (next != (QActive *)0) && (prio_in <= QF_MAX_ACTIVE));
- /* QXK Context switch callback defined or QS tracing enabled? */
- #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
- QXK_contextSw(next);
- #endif /* QF_ON_CONTEXT_SW || Q_SPY */
- QXK_attr_.next = (QActive *)0; /* clear the next AO */
- QXK_attr_.curr = (QActive *)0; /* current is basic-thread */
- /* priority of the next thread */
- uint8_t p = next->prio;
- /* loop until no more ready-to-run AOs of higher prio than the initial */
- do {
- QXK_attr_.actPrio = p; /* next active prio */
- QF_INT_ENABLE(); /* unconditionally enable interrupts */
- /* perform the run-to-completion (RTC) step...
- * 1. retrieve the event from the AO's event queue, which by this
- * time must be non-empty and QActive_get_() asserts it.
- * 2. dispatch the event to the AO's state machine.
- * 3. determine if event is garbage and collect it if so
- */
- QEvt const * const e = QActive_get_(next);
- QHSM_DISPATCH(&next->super, e, next->prio);
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e);
- #endif
- QF_INT_DISABLE(); /* unconditionally disable interrupts */
- if (next->eQueue.frontEvt == (QEvt *)0) { /* empty queue? */
- QPSet_remove(&QF_readySet_, p);
- }
- if (QPSet_isEmpty(&QF_readySet_)) {
- QXK_attr_.next = (QActive *)0;
- next = QActive_registry_[0];
- p = 0U; /* no activation needed */
- }
- else {
- /* find next highest-prio below the lock ceiling */
- p = (uint8_t)QPSet_findMax(&QF_readySet_);
- if (p <= QXK_attr_.lockCeil) {
- p = QXK_attr_.lockHolder; /* thread holding lock */
- if (p != 0U) {
- Q_ASSERT_ID(710, QPSet_hasElement(&QF_readySet_, p));
- }
- }
- /* set the next thread and ensure that it is registered */
- next = QActive_registry_[p];
- Q_ASSERT_ID(720, next != (QActive *)0);
- /* is next a basic thread? */
- if (next->osObject == (void *)0) {
- /* is the next priority above the initial priority? */
- if (p > QActive_registry_[prio_in]->prio) {
- #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
- if (p != QXK_attr_.actPrio) { /* changing threads? */
- QXK_contextSw(next);
- }
- #endif /* QF_ON_CONTEXT_SW || Q_SPY */
- QXK_attr_.next = next;
- }
- else {
- QXK_attr_.next = (QActive *)0;
- p = 0U; /* no activation needed */
- }
- }
- else { /* next is the extended-thread */
- QXK_attr_.next = next;
- QXK_CONTEXT_SWITCH_();
- p = 0U; /* no activation needed */
- }
- }
- } while (p != 0U); /* while activation needed */
- /* restore the active priority */
- QXK_attr_.actPrio = prio_in;
- #if (defined QF_ON_CONTEXT_SW) || (defined Q_SPY)
- if (next->osObject == (void *)0) {
- QXK_contextSw((prio_in == 0U)
- ? (QActive *)0
- : QActive_registry_[prio_in]);
- }
- #endif /* QF_ON_CONTEXT_SW || Q_SPY */</code>
- </operation>
- <!--${QXK::QXK-extern-C::current}-->
- <operation name="current" type="QActive *" visibility="0x00" properties="0x00">
- <documentation>/*! obtain the currently executing active-object/thread
- * @static @public @memberof QXK
- *
- * @returns
- * pointer to the currently executing active-object/thread
- *
- * @precondition{qxk,800}
- * - the QXK kernel must be running
- *
- * @postcondition{qxk,890}
- * - the current thread must be valid
- */
- /*! @static @public @memberof QXK */</documentation>
- <code>Q_REQUIRE_ID(800, QXK_attr_.lockCeil <= QF_MAX_ACTIVE);
- QF_CRIT_STAT_
- QF_CRIT_E_();
- struct QActive *curr = QXK_attr_.curr;
- if (curr == (QActive *)0) { /* basic thread? */
- curr = QActive_registry_[QXK_attr_.actPrio];
- }
- QF_CRIT_X_();
- Q_ENSURE_ID(890, curr != (QActive *)0);
- return curr;</code>
- </operation>
- <!--${QXK::QXK-extern-C::stackInit_}-->
- <operation name="stackInit_" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! initialize the private stack of a given AO (defined in QXK port)
- * @static @private @memberof QXK
- */
- /*! @static @private @memberof QXK */</documentation>
- <!--${QXK::QXK-extern-C::stackInit_::thr}-->
- <parameter name="thr" type="void *"/>
- <!--${QXK::QXK-extern-C::stackInit_::handler}-->
- <parameter name="handler" type=" QXThreadHandler const"/>
- <!--${QXK::QXK-extern-C::stackInit_::stkSto}-->
- <parameter name="stkSto" type="void * const"/>
- <!--${QXK::QXK-extern-C::stackInit_::stkSize}-->
- <parameter name="stkSize" type="uint_fast16_t const"/>
- </operation>
- <!--${QXK::QXK-extern-C::contextSw}-->
- <operation name="contextSw? defined(Q_SPY) || defined(QF_ON_CONTEXT_SW)" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! QXK context switch management
- * @static @public @memberof QXK
- *
- * @details
- * This function performs software tracing (if #Q_SPY is defined)
- * and calls QF_onContextSw() (if #QF_ON_CONTEXT_SW is defined)
- *
- * @param[in] next pointer to the next thread (NULL for basic-thread)
- *
- * @attention
- * QXK_contextSw() is invoked with interrupts **disabled** and must also
- * return with interrupts **disabled**.
- */
- /*! @static @public @memberof QXK */</documentation>
- <!--${QXK::QXK-extern-C::contextSw::next}-->
- <parameter name="next" type="QActive * const"/>
- <code>#ifdef Q_SPY
- uint8_t const prev_prio = (QXK_attr_.prev != (QActive *)0)
- ? QXK_attr_.prev->prio
- : 0U;
- #endif /* Q_SPY */
- if (next != (QActive *)0) { /* next is NOT idle? */
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_NEXT, next->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_2U8_PRE_(next->prio, prev_prio);
- QS_END_NOCRIT_PRE_()
- }
- else { /* going to idle */
- QS_BEGIN_NOCRIT_PRE_(QS_SCHED_IDLE, prev_prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_U8_PRE_(prev_prio);
- QS_END_NOCRIT_PRE_()
- }
- #ifdef QF_ON_CONTEXT_SW
- QF_onContextSw(QXK_attr_.prev, next);
- #endif /* QF_ON_CONTEXT_SW */
- QXK_attr_.prev = next; /* update the previous thread */</code>
- </operation>
- </package>
- </package>
- <!--${QXK-macros}-->
- <package name="QXK-macros" stereotype="0x02">
- <!--${QXK-macros::QXTHREAD_START}-->
- <operation name="QXTHREAD_START" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Virtual call to start an extened thread
- *
- * @details
- * Starts execution of the thread and registers the AO with the framework.
- *
- * @param[in,out] me_ current instance pointer (see @ref oop)
- * @param[in] prioSpec_ priority specification at which to start the
- * extended thread (see ::QPrioSpec)
- * @param[in] qSto_ pointer to the storage for the ring buffer of the
- * event queue (used only with the built-in ::QEQueue)
- * @param[in] qLen_ length of the event queue (in events)
- * @param[in] stkSto_ pointer to the stack storage (used only when
- * per-AO stack is needed)
- * @param[in] stkSize_ stack size (in bytes)
- * @param[in] par_ pointer to the additional port-specific parameter(s)
- * (might be NULL).
- * @usage
- * @include qxk_start.c
- */</documentation>
- <!--${QXK-macros::QXTHREAD_START::me_}-->
- <parameter name="me_" type="<QActive subclass *>"/>
- <!--${QXK-macros::QXTHREAD_START::prioSpec_}-->
- <parameter name="prioSpec_" type="QPrioSpec const"/>
- <!--${QXK-macros::QXTHREAD_START::qSto_}-->
- <parameter name="qSto_" type="QEvt const * *"/>
- <!--${QXK-macros::QXTHREAD_START::qLen_}-->
- <parameter name="qLen_" type="uint_fast16_t"/>
- <!--${QXK-macros::QXTHREAD_START::stkSto_}-->
- <parameter name="stkSto_" type="void *"/>
- <!--${QXK-macros::QXTHREAD_START::stkSize_}-->
- <parameter name="stkSize_" type="uint_fast16_t"/>
- <!--${QXK-macros::QXTHREAD_START::par_}-->
- <parameter name="par_" type="void const *"/>
- <code>\
- do { \
- Q_ASSERT((me_)->super.super.vptr); \
- ((*((QActiveVtable const *)((me_)->super.super.vptr))->start)( \
- &(me_)->super, (prioSpec_), (QEvt const **)(qSto_), (qLen_), \
- (stkSto_), (stkSize_), (par_))); \
- } while (false)</code>
- </operation>
- <!--${QXK-macros::QXTHREAD_NO_TIMEOUT}-->
- <attribute name="QXTHREAD_NO_TIMEOUT" type="uint_fast16_t" visibility="0x03" properties="0x00">
- <documentation>/*! No-timeout when blocking on semaphores, mutextes, and queues */</documentation>
- <code>((uint_fast16_t)0)</code>
- </attribute>
- <!--${QXK-macros::QXTHREAD_POST_X}-->
- <operation name="QXTHREAD_POST_X" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Asynchronous posting events to the event queue of an eXtended thread
- * @details
- * This macro does not assert if the queue overflows and cannot accept
- * the event with the specified margin of free slots remaining.
- *
- * @param[in,out] me_ current instance pointer (see @ref oop)
- * @param[in] e_ pointer to the event to post
- * @param[in] margin_ the minimum free slots in the queue, which
- * must still be available after posting the event.
- * The special value #QF_NO_MARGIN causes asserting
- * failure in case event allocation fails.
- * @param[in] sender_ pointer to the sender object (used in QS tracing)
- *
- * @returns
- * 'true' if the posting succeeded, and 'false' if the posting failed due
- * to insufficient margin of free slots available in the queue.
- *
- * @note
- * The `sender_` parameter is actually only used when QS tracing is enabled
- * (macro #Q_SPY is defined). When QS software tracing is disabled, the
- * QXTHREAD_POST_X() macro does not pass the `sender_` parameter, so the
- * overhead of passing this extra argument is entirely avoided.
- *
- * @note
- * The pointer to the sender object is not necessarily a pointer to an
- * active object. In fact, if QXTHREAD_POST_X() is called from an interrupt
- * or other context, you can create a unique object just to unambiguously
- * identify the sender of the event.
- *
- * @usage
- * @include qf_postx.c
- */</documentation>
- <!--${QXK-macros::QXTHREAD_POST_X::me_}-->
- <parameter name="me_" type="<QActive subclass *>"/>
- <!--${QXK-macros::QXTHREAD_POST_X::e_}-->
- <parameter name="e_" type="QEvt const *"/>
- <!--${QXK-macros::QXTHREAD_POST_X::margin_}-->
- <parameter name="margin_" type="uint16_t"/>
- <!--${QXK-macros::QXTHREAD_POST_X::sender_}-->
- <parameter name="sender_" type="<sender *>"/>
- <code>\
- QACTIVE_POST_X(&(me_)->super, (e_), (margin_), (sender_))</code>
- </operation>
- </package>
- <!--${QXK-impl}-->
- <package name="QXK-impl" stereotype="0x02">
- <!--${QXK-impl::QXK_ISR_CONTEXT_}-->
- <operation name="QXK_ISR_CONTEXT_?ndef QXK_ISR_CONTEXT_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! Internal macro that reports the execution context (ISR vs. thread)
- *
- * @returns true if the code executes in the ISR context and false
- * otherwise
- */</documentation>
- <code>(QF_intNest_ != 0U)</code>
- </operation>
- <!--${QXK-impl::QF_SCHED_STAT_}-->
- <attribute name="QF_SCHED_STAT_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QXK scheduler lock status */</documentation>
- <code>QSchedStatus lockStat_;</code>
- </attribute>
- <!--${QXK-impl::QF_SCHED_LOCK_}-->
- <operation name="QF_SCHED_LOCK_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QXK selective scheduler locking */</documentation>
- <!--${QXK-impl::QF_SCHED_LOCK_::ceil_}-->
- <parameter name="ceil_" type="uint_fast8_t"/>
- <code>do { \
- if (QXK_ISR_CONTEXT_()) { \
- lockStat_ = 0xFFU; \
- } else { \
- lockStat_ = QXK_schedLock((ceil_)); \
- } \
- } while (false)</code>
- </operation>
- <!--${QXK-impl::QF_SCHED_UNLOCK_}-->
- <operation name="QF_SCHED_UNLOCK_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QXK selective scheduler unlocking */</documentation>
- <code>do { \
- if (lockStat_ != 0xFFU) { \
- QXK_schedUnlock(lockStat_); \
- } \
- } while (false)</code>
- </operation>
- <!--${QXK-impl::QACTIVE_EQUEUE_WAIT_}-->
- <operation name="QACTIVE_EQUEUE_WAIT_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QXK native event queue waiting */</documentation>
- <!--${QXK-impl::QACTIVE_EQUEUE_W~::me_}-->
- <parameter name="me_" type="QActive *"/>
- <code>\
- (Q_ASSERT_ID(110, (me_)->eQueue.frontEvt != (QEvt *)0))</code>
- </operation>
- <!--${QXK-impl::QACTIVE_EQUEUE_SIGNAL_}-->
- <operation name="QACTIVE_EQUEUE_SIGNAL_" type="" visibility="0x03" properties="0x00">
- <documentation>/*! QXK native event queue signaling */</documentation>
- <!--${QXK-impl::QACTIVE_EQUEUE_S~::me_}-->
- <parameter name="me_" type="QActive *"/>
- <code>do { \
- QPSet_insert(&QF_readySet_, (uint_fast8_t)(me_)->prio); \
- if (!QXK_ISR_CONTEXT_()) { \
- if (QXK_sched_() != 0U) { \
- QXK_activate_(); \
- } \
- } \
- } while (false)</code>
- </operation>
- <!--${QXK-impl::QXK_PTR_CAST_}-->
- <operation name="QXK_PTR_CAST_" type="QXThread *" visibility="0x03" properties="0x00">
- <specifiers><type_></specifiers>
- <documentation>/*! internal macro to encapsulate casting of pointers for MISRA deviations
- *
- * @details
- * This macro is specifically and exclusively used for casting pointers
- * that are never de-referenced, but only used for internal bookkeeping and
- * checking (via assertions) the correct operation of the QXK kernel.
- * Such pointer casting is not compliant with MISRA-2012-Rule 11.3(req)
- * as well as other messages (e.g., PC-Lint-Plus warning 826).
- * Defining this specific macro for this purpose allows to selectively
- * disable the warnings for this particular case.
- */</documentation>
- <!--${QXK-impl::QXK_PTR_CAST_::type_}-->
- <parameter name="type_" type="<QXK obj>"/>
- <!--${QXK-impl::QXK_PTR_CAST_::ptr_}-->
- <parameter name="ptr_" type="QActive *"/>
- <code>((type_)(ptr_))</code>
- </operation>
- <!--${QXK-impl::QXTHREAD_CAST_}-->
- <operation name="QXTHREAD_CAST_" type="QXThread *" visibility="0x03" properties="0x00">
- <documentation>/*! internal macro to encapsulate casting of pointers for MISRA deviations
- *
- * @details
- * This macro is specifically and exclusively used for downcasting pointers
- * to QActive to pointers to QXThread in situations when it is known
- * that such downcasting is correct.However, such pointer casting is not
- * compliant with MISRA-2012-Rule 11.3(req) as well as other messages (e.g.,
- * PC-Lint-Plus warning 826). Defining this specific macro for this purpose
- * allows to selectively disable the warnings for this particular case.
- */</documentation>
- <!--${QXK-impl::QXTHREAD_CAST_::ptr_}-->
- <parameter name="ptr_" type="QActive *"/>
- <code>((QXThread *)(ptr_))</code>
- </operation>
- <!--${QXK-impl::QXK_threadExit_}-->
- <operation name="QXK_threadExit_" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! called when QXThread exits
- * @private @memberof QXThread
- *
- * @details
- * Called when the extended-thread handler function returns.
- *
- * @precondition{qxk,900}
- * - must NOT be called from an ISR;
- * - must be called from an extended thread
- * @precondition{qxk,901}
- * - the thread must NOT be holding a scheduler lock
- *
- * @note
- * Most thread handler functions are structured as endless loops that never
- * return. But it is also possible to structure threads as one-shot functions
- * that perform their job and return. In that case this function peforms
- * cleanup after the thread.
- */
- /*! @private @memberof QXThread */</documentation>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QXThread const * const thr = QXTHREAD_CAST_(QXK_attr_.curr);
- Q_REQUIRE_ID(900, (!QXK_ISR_CONTEXT_()) /* can't be in the ISR context */
- && (thr != (QXThread *)0)); /* current thread must be extended */
- Q_REQUIRE_ID(901, QXK_attr_.lockHolder != thr->super.prio);
- uint_fast8_t const p = (uint_fast8_t)thr->super.prio;
- /* remove this thread from the QF */
- QActive_registry_[p] = (QActive *)0;
- QPSet_remove(&QF_readySet_, p);
- (void)QXK_sched_(); /* schedule other threads */
- QF_CRIT_X_();</code>
- </operation>
- </package>
- <!--${QS-config}-->
- <package name="QS-config" stereotype="0x02">
- <!--${QS-config::QS_CTR_SIZE}-->
- <attribute name="QS_CTR_SIZE?ndef QS_CTR_SIZE" type="unsigned" visibility="0x03" properties="0x00">
- <documentation>/*! The size [bytes] of the internal QS buffer-counters. Valid values: 2U or 4U;
- * default 2U.
- *
- * @details
- * This macro can be defined in the QS port file (qs_port.h) to
- * configure the ::QSCtr type. Here the macro is not defined so the
- * default of 2 byte is chosen.
- */</documentation>
- <code>2U</code>
- </attribute>
- <!--${QS-config::QS_CTR_SIZE defined incorrectly,~}-->
- <attribute name="QS_CTR_SIZE defined incorrectly, expected 2U or 4U? (QS_CTR_SIZE != 2U) && (QS_CTR_SIZE != 4U)" type="#error" visibility="0x04" properties="0x00"/>
- <!--${QS-config::QS_TIME_SIZE}-->
- <attribute name="QS_TIME_SIZE?ndef QS_TIME_SIZE" type="unsigned" visibility="0x03" properties="0x00">
- <documentation>/*! The size [bytes] of the QS time stamp. Valid values: 1U, 2U, or 4U;
- * default 4U.
- *
- * @details
- * This macro can be defined in the QS port file (qs_port.h) to
- * configure the ::QSTimeCtr type. Here the macro is not defined so the
- * default of 4 byte is chosen.
- */</documentation>
- <code>4U</code>
- </attribute>
- <!--${QS-config::QS_TIME_SIZE defined incorrectly~}-->
- <attribute name="QS_TIME_SIZE defined incorrectly, expected 1U, 2U, or 4U? (QS_TIME_SIZE != 1U) && (QS_TIME_SIZE != 2U) && (QS_TIME_SIZE != 4U)" type="#error" visibility="0x04" properties="0x00"/>
- </package>
- <!--${QS-macros}-->
- <package name="QS-macros" stereotype="0x02">
- <!--${QS-macros::QS_INIT}-->
- <operation name="QS_INIT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Initialize the QS facility
- *
- * @details
- * This macro provides an indirection layer to invoke the QS initialization
- * routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
- * @sa QS_onStartup(), example of setting up a QS filter in
- * QS_GLB_FILTER()
- */</documentation>
- <!--${QS-macros::QS_INIT::arg_}-->
- <parameter name="arg_" type="void *"/>
- <code>(QS_onStartup(arg_))</code>
- </operation>
- <!--${QS-macros::QS_EXIT}-->
- <operation name="QS_EXIT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Cleanup the QS facility
- *
- * @details
- * This macro provides an indirection layer to invoke the QS cleanup
- * routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
- * @sa QS_onCleanup()
- */</documentation>
- <code>(QS_onCleanup())</code>
- </operation>
- <!--${QS-macros::QS_OUTPUT}-->
- <operation name="QS_OUTPUT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! macro to handle the QS output from the application
- *
- * @note
- * If this macro is used, the application must define QS_output().
- */</documentation>
- <code>(QS_output())</code>
- </operation>
- <!--${QS-macros::QS_RX_INPUT}-->
- <operation name="QS_RX_INPUT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! macro to handle the QS-RX input to the application
- *
- * @note
- * If this macro is used, the application must define QS_doInput().
- */</documentation>
- <code>(QS_rx_input())</code>
- </operation>
- <!--${QS-macros::QS_GLB_FILTER}-->
- <operation name="QS_GLB_FILTER" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Global Filter ON for a given record type `rec_`
- *
- * @details
- * This macro provides an indirection layer to call QS_filterOn()
- * if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
- *
- * @sa
- * - enum QSpyGroups - QS record groups that can be used as `rec_`
- * - enum QSpyPre - predefined QS records that can be used as `rec_`
- *
- * @usage
- * The following example shows how to use QS filters:
- * @include qs_filter.c
- */</documentation>
- <!--${QS-macros::QS_GLB_FILTER::rec_}-->
- <parameter name="rec_" type="uint8_t"/>
- <code>(QS_glbFilter_((int_fast16_t)(rec_)))</code>
- </operation>
- <!--${QS-macros::QS_LOC_FILTER}-->
- <operation name="QS_LOC_FILTER" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Local Filter for a given state machine object `qs_id`
- *
- * @details
- * This macro provides an indirection layer to call QS_locFilter_()
- * if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
- *
- * @sa
- * - enum QSpyIdGroups - QS ID groups that can be used as `qs_id_`
- * - enum QSpyIdOffsets - QS ID offsets for `qs_id_` (e.g., QS_AP_IDS + 5)
- *
- * The following example shows how to use QS filters:
- * @include qs_filter.c
- */</documentation>
- <!--${QS-macros::QS_LOC_FILTER::qs_id_}-->
- <parameter name="qs_id_" type="uint8_t"/>
- <code>(QS_locFilter_((int_fast16_t)(qs_id_)))</code>
- </operation>
- <!--${QS-macros::QS_BEGIN_ID}-->
- <operation name="QS_BEGIN_ID" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Begin an application-specific QS record with entering critical section
- *
- * @details
- * The following example shows how to build a user QS record using the
- * macros QS_BEGIN_ID(), QS_END(), and the formatted output macros:
- * QS_U8(), QS_STR(), etc.
- *
- * @note
- * Must always be used in pair with QS_END()
- *
- * @include qs_ap.c
- */</documentation>
- <!--${QS-macros::QS_BEGIN_ID::rec_}-->
- <parameter name="rec_" type="uint8_t"/>
- <!--${QS-macros::QS_BEGIN_ID::qs_id_}-->
- <parameter name="qs_id_" type="uint8_t"/>
- <code>\
- if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \
- QS_CRIT_STAT_ \
- QS_CRIT_E_(); \
- QS_beginRec_((uint_fast8_t)(rec_)); \
- QS_TIME_PRE_(); {</code>
- </operation>
- <!--${QS-macros::QS_END}-->
- <operation name="QS_END" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! End an application-specific QS record with exiting critical section.
- *
- * @sa example for QS_BEGIN_ID()
- * @note Must always be used in pair with QS_BEGIN_ID()
- */</documentation>
- <code>} \
- QS_endRec_(); \
- QS_CRIT_X_(); \
- }</code>
- </operation>
- <!--${QS-macros::QS_FLUSH}-->
- <operation name="QS_FLUSH" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Flush the QS trace data to the host
- *
- * @details
- * This macro invokes the QS_flush() platform-dependent callback
- * function to flush the QS trace buffer to the host. The function
- * typically busy-waits until all the data in the buffer is sent to
- * the host. This is acceptable only in the initial transient.
- */</documentation>
- <code>(QS_onFlush())</code>
- </operation>
- <!--${QS-macros::QS_BEGIN_NOCRIT}-->
- <operation name="QS_BEGIN_NOCRIT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Begin an application-specific QS record WITHOUT entering critical section */</documentation>
- <!--${QS-macros::QS_BEGIN_NOCRIT::rec_}-->
- <parameter name="rec_" type="uint8_t"/>
- <!--${QS-macros::QS_BEGIN_NOCRIT::qs_id_}-->
- <parameter name="qs_id_" type="uint8_t"/>
- <code>\
- if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \
- QS_beginRec_((uint_fast8_t)(rec_)); \
- QS_TIME_PRE_(); {</code>
- </operation>
- <!--${QS-macros::QS_END_NOCRIT}-->
- <operation name="QS_END_NOCRIT" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! End an application-specific QS record WITHOUT exiting critical section */</documentation>
- <code>} \
- QS_endRec_();\
- }</code>
- </operation>
- <!--${QS-macros::QS_GLB_CHECK_}-->
- <operation name="QS_GLB_CHECK_" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Helper macro for checking the global QS filter */</documentation>
- <!--${QS-macros::QS_GLB_CHECK_::rec_}-->
- <parameter name="rec_" type="uint8_t"/>
- <code>\
- (((uint_fast8_t)QS_priv_.glbFilter[(uint_fast8_t)(rec_) >> 3U] \
- & ((uint_fast8_t)1U << ((uint_fast8_t)(rec_) & 7U))) != 0U)</code>
- </operation>
- <!--${QS-macros::QS_LOC_CHECK_}-->
- <operation name="QS_LOC_CHECK_" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Helper macro for checking the local QS filter */</documentation>
- <!--${QS-macros::QS_LOC_CHECK_::qs_id_}-->
- <parameter name="qs_id_" type="uint8_t"/>
- <code>\
- (((uint_fast8_t)QS_priv_.locFilter[(uint_fast8_t)(qs_id_) >> 3U] \
- & ((uint_fast8_t)1U << ((uint_fast8_t)(qs_id_) & 7U))) != 0U)</code>
- </operation>
- <!--${QS-macros::QS_REC_DONE}-->
- <operation name="QS_REC_DONE?ndef QS_REC_DONE" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Macro to execute user code when a QS record is produced
- *
- * @note
- * This is a dummy definition in case this macro is undefined.
- */</documentation>
- <code>((void)0)</code>
- </operation>
- <!--${QS-macros::QS_I8}-->
- <operation name="QS_I8" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted int8_t to the QS record */</documentation>
- <!--${QS-macros::QS_I8::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_I8::data_}-->
- <parameter name="data_" type="int8_t"/>
- <code>\
- (QS_u8_fmt_((uint8_t)(((width_) << 4U) & 0x7U) | (uint8_t)QS_I8_ENUM_T, \
- (data_)))</code>
- </operation>
- <!--${QS-macros::QS_U8}-->
- <operation name="QS_U8" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted uint8_t to the QS record */</documentation>
- <!--${QS-macros::QS_U8::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_U8::data_}-->
- <parameter name="data_" type="std:u:int8_t"/>
- <code>\
- (QS_u8_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U8_T, (data_)))</code>
- </operation>
- <!--${QS-macros::QS_I16}-->
- <operation name="QS_I16" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted int16_t to the QS record */</documentation>
- <!--${QS-macros::QS_I16::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_I16::data_}-->
- <parameter name="data_" type="int16_t"/>
- <code>\
- (QS_u16_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I16_T, (data_)))</code>
- </operation>
- <!--${QS-macros::QS_U16}-->
- <operation name="QS_U16" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted uint16_t to the QS record */</documentation>
- <!--${QS-macros::QS_U16::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_U16::data_}-->
- <parameter name="data_" type="std:u:int16_t"/>
- <code>\
- (QS_u16_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U16_T, (data_)))</code>
- </operation>
- <!--${QS-macros::QS_I32}-->
- <operation name="QS_I32" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted int32_t to the QS record */</documentation>
- <!--${QS-macros::QS_I32::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_I32::data_}-->
- <parameter name="data_" type="int32_t"/>
- <code>\
- (QS_u32_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I32_T, (data_)))</code>
- </operation>
- <!--${QS-macros::QS_U32}-->
- <operation name="QS_U32" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted uint32_t to the QS record */</documentation>
- <!--${QS-macros::QS_U32::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_U32::data_}-->
- <parameter name="data_" type="std:u:int32_t"/>
- <code>\
- (QS_u32_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U32_T, (data_)))</code>
- </operation>
- <!--${QS-macros::QS_I64}-->
- <operation name="QS_I64" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted int64_t to the QS record */</documentation>
- <!--${QS-macros::QS_I64::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_I64::data_}-->
- <parameter name="data_" type="int64_t"/>
- <code>\
- (QS_u64_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_I64_T, (data_)))</code>
- </operation>
- <!--${QS-macros::QS_U64}-->
- <operation name="QS_U64" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted uint64_t to the QS record */</documentation>
- <!--${QS-macros::QS_U64::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_U64::data_}-->
- <parameter name="data_" type="std:u:int64_t"/>
- <code>\
- (QS_u64_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_U64_T, (data_)))</code>
- </operation>
- <!--${QS-macros::QS_F32}-->
- <operation name="QS_F32" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted 32-bit floating point number to the QS record */</documentation>
- <!--${QS-macros::QS_F32::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_F32::data_}-->
- <parameter name="data_" type="float32_t"/>
- <code>\
- (QS_f32_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_F32_T, (data_)))</code>
- </operation>
- <!--${QS-macros::QS_F64}-->
- <operation name="QS_F64" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted 64-bit floating point number to the QS record */</documentation>
- <!--${QS-macros::QS_F64::width_}-->
- <parameter name="width_" type="uint8_t"/>
- <!--${QS-macros::QS_F64::data_}-->
- <parameter name="data_" type="float64_t"/>
- <code>\
- (QS_f64_fmt_((uint8_t)(((width_) << 4)) | (uint8_t)QS_F64_T, (data_)))</code>
- </operation>
- <!--${QS-macros::QS_STR}-->
- <operation name="QS_STR" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted zero-terminated ASCII string to the QS record */</documentation>
- <!--${QS-macros::QS_STR::str_}-->
- <parameter name="str_" type="char const *"/>
- <code>(QS_str_fmt_((str_)))</code>
- </operation>
- <!--${QS-macros::QS_MEM}-->
- <operation name="QS_MEM" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted memory block of up to 255 bytes to the QS record */</documentation>
- <!--${QS-macros::QS_MEM::mem_}-->
- <parameter name="mem_" type="void *"/>
- <!--${QS-macros::QS_MEM::size_}-->
- <parameter name="size_" type="std:u:int8_t"/>
- <code>(QS_mem_fmt_((mem_), (size_)))</code>
- </operation>
- <!--${QS-macros::QS_ENUM}-->
- <operation name="QS_ENUM" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted enumeration to the QS record */</documentation>
- <!--${QS-macros::QS_ENUM::group_}-->
- <parameter name="group_" type="uint8_t const"/>
- <!--${QS-macros::QS_ENUM::value_}-->
- <parameter name="value_" type="enum_t const"/>
- <code>\
- (QS_u8_fmt_((uint8_t)(0x80U | ((group_) << 4U)) | (uint8_t)QS_I8_ENUM_T,\
- (uint8_t)(value_)))</code>
- </operation>
- <!--${QS-macros::QS_TIME_PRE_}-->
- <operation name="QS_TIME_PRE_? (QS_TIME_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output time stamp to a QS record (used in predefined
- * and application-specific trace records)
- */</documentation>
- <code>(QS_u32_raw_(QS_onGetTime()))</code>
- </operation>
- <!--${QS-macros::QS_TIME_PRE_}-->
- <operation name="QS_TIME_PRE_? (QS_TIME_SIZE == 2U)" type="void" visibility="0x03" properties="0x00">
- <code>(QS_u16_raw_(QS_onGetTime()))</code>
- </operation>
- <!--${QS-macros::QS_TIME_PRE_}-->
- <operation name="QS_TIME_PRE_? (QS_TIME_SIZE == 1U)" type="void" visibility="0x03" properties="0x00">
- <code>(QS_u8_raw_(QS_onGetTime()))</code>
- </operation>
- <!--${QS-macros::QS_OBJ}-->
- <operation name="QS_OBJ? (QS_OBJ_PTR_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted object pointer to the QS record */</documentation>
- <!--${QS-macros::QS_OBJ::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <code>(QS_u32_fmt_(QS_OBJ_T, (uint32_t)(obj_)))</code>
- </operation>
- <!--${QS-macros::QS_OBJ}-->
- <operation name="QS_OBJ? (QS_OBJ_PTR_SIZE == 2U)" type="void" visibility="0x03" properties="0x00">
- <!--${QS-macros::QS_OBJ::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <code>(QS_u16_fmt_(QS_OBJ_T, (uint16_t)(obj_)))</code>
- </operation>
- <!--${QS-macros::QS_OBJ}-->
- <operation name="QS_OBJ? (QS_OBJ_PTR_SIZE == 1U)" type="void" visibility="0x03" properties="0x00">
- <!--${QS-macros::QS_OBJ::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <code>(QS_u8_fmt_(QS_OBJ_T, (uint8_t)(obj_)))</code>
- </operation>
- <!--${QS-macros::QS_OBJ}-->
- <operation name="QS_OBJ? (QS_OBJ_PTR_SIZE == 8U)" type="void" visibility="0x03" properties="0x00">
- <!--${QS-macros::QS_OBJ::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <code>(QS_u64_fmt_(QS_OBJ_T, (uint64_t)(obj_)))</code>
- </operation>
- <!--${QS-macros::QS_FUN}-->
- <operation name="QS_FUN? (QS_FUN_PTR_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
- <documentation>/* Output formatted function pointer to the QS record */</documentation>
- <!--${QS-macros::QS_FUN::fun_}-->
- <parameter name="fun_" type="QSpyFunPtr"/>
- <code>(QS_u32_fmt_(QS_FUN_T, (uint32_t)(fun_)))</code>
- </operation>
- <!--${QS-macros::QS_FUN}-->
- <operation name="QS_FUN? (QS_FUN_PTR_SIZE == 2U)" type="void" visibility="0x03" properties="0x00">
- <!--${QS-macros::QS_FUN::fun_}-->
- <parameter name="fun_" type="QSpyFunPtr"/>
- <code>(QS_u16_fmt_(QS_FUN_T, (uint16_t)(fun_)))</code>
- </operation>
- <!--${QS-macros::QS_FUN}-->
- <operation name="QS_FUN? (QS_FUN_PTR_SIZE == 1U)" type="void" visibility="0x03" properties="0x00">
- <!--${QS-macros::QS_FUN::fun_}-->
- <parameter name="fun_" type="QSpyFunPtr"/>
- <code>(QS_u8_fmt_(QS_FUN_T, (uint8_t)(fun_)))</code>
- </operation>
- <!--${QS-macros::QS_FUN}-->
- <operation name="QS_FUN? (QS_FUN_PTR_SIZE == 8U)" type="void" visibility="0x03" properties="0x00">
- <!--${QS-macros::QS_FUN::fun_}-->
- <parameter name="fun_" type="QSpyFunPtr"/>
- <code>(QS_u64_fmt_(QS_FUN_T, (uint64_t)(fun_)))</code>
- </operation>
- <!--${QS-macros::QS_SIG}-->
- <operation name="QS_SIG? (Q_SIGNAL_SIZE == 4U)" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output formatted event signal (of type ::QSignal) and
- * the state machine object to the user QS record
- */</documentation>
- <!--${QS-macros::QS_SIG::sig_}-->
- <parameter name="sig_" type="QSignal"/>
- <!--${QS-macros::QS_SIG::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <code>\
- QS_u32_fmt_(QS_SIG_T, (sig_)); \
- QS_obj_raw_(obj_)</code>
- </operation>
- <!--${QS-macros::QS_SIG}-->
- <operation name="QS_SIG? (Q_SIGNAL_SIZE == 2U)" type="void" visibility="0x03" properties="0x00">
- <!--${QS-macros::QS_SIG::sig_}-->
- <parameter name="sig_" type="QSignal"/>
- <!--${QS-macros::QS_SIG::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <code>\
- QS_u16_fmt_(QS_SIG_T, (sig_)); \
- QS_obj_raw_(obj_)</code>
- </operation>
- <!--${QS-macros::QS_SIG}-->
- <operation name="QS_SIG? (Q_SIGNAL_SIZE == 1U)" type="void" visibility="0x03" properties="0x00">
- <!--${QS-macros::QS_SIG::sig_}-->
- <parameter name="sig_" type="QSignal"/>
- <!--${QS-macros::QS_SIG::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <code>\
- QS_u8_fmt_(QS_SIG_T, (sig_)); \
- QS_obj_raw_(obj_)</code>
- </operation>
- <!--${QS-macros::QS_SIG_DICTIONARY}-->
- <operation name="QS_SIG_DICTIONARY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output QS signal dictionary record
- *
- * @details
- * A signal dictionary record associates the numerical value of the signal
- * and the binary address of the state machine that consumes that signal
- * with the human-readable name of the signal.
- *
- * @param[in] sig_ event signal (typically enumerated, e.g. `TIMEOUT_SIG`)
- * @param[in] obj_ pointer to the associated state machine object
- * (might be `(void*)0` for globally recognized signals)
- *
- * A signal dictionary entry is associated with both the signal value `sig_`
- * and the state machine `obj_`, because signals are required to be unique
- * only within a given state machine and therefore the same numerical values
- * can represent different signals in different state machines.
- *
- * For the "global" signals that have the same meaning in many state machines
- * (such as globally published signals), you can specify a signal dictionary
- * entry with the `obj_` parameter set to `(void*)0`.
- *
- * The following example shows the definition of signal dictionary entries
- * in the initial transition of the Table active object. Please note that
- * signals HUNGRY_SIG and DONE_SIG are associated with the Table state
- * machine only ("me" `obj_` pointer). The EAT_SIG signal, on the other
- * hand, is global (0 `obj_` pointer):
- * @include qs_sigDic.c
- *
- * The following QSpy log example shows the signal dictionary records
- * generated from the Table initial transition and subsequent records that
- * show human-readable names of the signals:
- * @include qs_sigLog.txt
- */</documentation>
- <!--${QS-macros::QS_SIG_DICTIONAR~::sig_}-->
- <parameter name="sig_" type="QSignal"/>
- <!--${QS-macros::QS_SIG_DICTIONAR~::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <code>\
- (QS_sig_dict_pre_((sig_), (obj_), #sig_))</code>
- </operation>
- <!--${QS-macros::QS_OBJ_DICTIONARY}-->
- <operation name="QS_OBJ_DICTIONARY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output object dictionary record
- *
- * @details
- * An object dictionary record associates the binary address of an object
- * in the target's memory with the human-readable name of the object.
- *
- * @param[in] obj_ pointer to the object (any object)
- *
- * The following example shows the definition of object dictionary entry
- * for the Table active object:
- * @include qs_objDic.c
- */</documentation>
- <!--${QS-macros::QS_OBJ_DICTIONAR~::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <code>\
- (QS_obj_dict_pre_((obj_), #obj_))</code>
- </operation>
- <!--${QS-macros::QS_OBJ_ARR_DICTIONARY}-->
- <operation name="QS_OBJ_ARR_DICTIONARY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output object-array dictionary record
- *
- * @details
- * An object array dictionary record associates the binary address of the
- * object element in the target's memory with the human-readable name
- * of the object.
- *
- * @param[in] obj_ pointer to the object (any object)
- * @param[in] idx_ array index
- *
- * The following example shows the definition of object array dictionary
- * for `Philo::inst[n]` and `Philo::inst[n].m_timeEvt`:
- * @include qs_objArrDic.c
- */</documentation>
- <!--${QS-macros::QS_OBJ_ARR_DICTI~::obj_}-->
- <parameter name="obj_" type="void const *"/>
- <!--${QS-macros::QS_OBJ_ARR_DICTI~::idx_}-->
- <parameter name="idx_" type="unsigned"/>
- <code>\
- (QS_obj_arr_dict_pre_((obj_), (idx_), #obj_))</code>
- </operation>
- <!--${QS-macros::QS_FUN_DICTIONARY}-->
- <operation name="QS_FUN_DICTIONARY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output function dictionary record
- *
- * @details
- * A function dictionary record associates the binary address of a function
- * in the target's memory with the human-readable name of the function.
- *
- * Providing a function dictionary QS record can vastly improve readability
- * of the QS log, because instead of dealing with cryptic machine addresses
- * the QSpy host utility can display human-readable function names.
- *
- * The example from #QS_SIG_DICTIONARY shows the definition of a function
- * dictionary.
- */</documentation>
- <!--${QS-macros::QS_FUN_DICTIONAR~::fun_}-->
- <parameter name="fun_" type="QSpyFunPtr"/>
- <code>\
- (QS_fun_dict_pre_((void (*)(void))(fun_), #fun_))</code>
- </operation>
- <!--${QS-macros::QS_USR_DICTIONARY}-->
- <operation name="QS_USR_DICTIONARY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output user QS record dictionary record
- *
- * @details
- * A user QS record dictionary record associates the numerical value of a
- * user record with the human-readable identifier.
- */</documentation>
- <!--${QS-macros::QS_USR_DICTIONAR~::rec_}-->
- <parameter name="rec_" type="unit8_t"/>
- <code>\
- (QS_usr_dict_pre_((rec_), #rec_))</code>
- </operation>
- <!--${QS-macros::QS_ENUM_DICTIONARY}-->
- <operation name="QS_ENUM_DICTIONARY" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Output enumeration dictionary record
- *
- * @details
- * An enum QS record dictionary record associates the numerical value of
- * an enumeration with the human-readable identifier.
- */</documentation>
- <!--${QS-macros::QS_ENUM_DICTIONA~::value_}-->
- <parameter name="value_" type="enum_t const"/>
- <!--${QS-macros::QS_ENUM_DICTIONA~::group_}-->
- <parameter name="group_" type="uint8_t const"/>
- <code>\
- (QS_enum_dict_pre_((value_), (group_), #value_))</code>
- </operation>
- <!--${QS-macros::QF_QS_CRIT_ENTRY}-->
- <operation name="QF_QS_CRIT_ENTRY" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Output the critical section entry record */</documentation>
- </operation>
- <!--${QS-macros::QF_QS_CRIT_EXIT}-->
- <operation name="QF_QS_CRIT_EXIT" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Output the critical section exit record */</documentation>
- </operation>
- <!--${QS-macros::QF_QS_ISR_ENTRY}-->
- <operation name="QF_QS_ISR_ENTRY" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Output the interrupt entry record *//*! Output the ISR entry */</documentation>
- <!--${QS-macros::QF_QS_ISR_ENTRY::isrnest}-->
- <parameter name="isrnest" type="uint_fast8_t const"/>
- <!--${QS-macros::QF_QS_ISR_ENTRY::prio_}-->
- <parameter name="prio_" type="uint_fast8_t const"/>
- <code>QS_BEGIN_NOCRIT_PRE_(QS_QF_ISR_ENTRY, 0U)
- QS_TIME_PRE_();
- QS_2u8_raw_(isrnest, prio);
- QS_END_NOCRIT_PRE_()</code>
- </operation>
- <!--${QS-macros::QF_QS_ISR_EXIT}-->
- <operation name="QF_QS_ISR_EXIT" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Output the ISR exit trace record */</documentation>
- <!--${QS-macros::QF_QS_ISR_EXIT::isrnest}-->
- <parameter name="isrnest" type="uint_fast8_t"/>
- <!--${QS-macros::QF_QS_ISR_EXIT::prio}-->
- <parameter name="prio" type="uint_fast8_t"/>
- <code>QS_BEGIN_NOCRIT_PRE_(QS_QF_ISR_EXIT, 0U)
- QS_TIME_PRE_();
- QS_2u8_raw_(isrnest, prio);
- QS_END_NOCRIT_PRE_()</code>
- </operation>
- <!--${QS-macros::QF_QS_ACTION}-->
- <operation name="QF_QS_ACTION" type="void" visibility="0x03" properties="0x00">
- <documentation>/*! Execute an action that is only necessary for QS output */</documentation>
- <!--${QS-macros::QF_QS_ACTION::act_}-->
- <parameter name="act_" type="<action code>"/>
- <code>(act_)</code>
- </operation>
- <!--${QS-macros::QS_EOD}-->
- <attribute name="QS_EOD" type="uint16_t" visibility="0x03" properties="0x00">
- <documentation>/*! Constant representing End-Of-Data condition returned from the
- * QS_getByte() function.
- */</documentation>
- <code>((uint16_t)0xFFFFU)</code>
- </attribute>
- <!--${QS-macros::QS_CMD}-->
- <attribute name="QS_CMD" type="uint8_t" visibility="0x03" properties="0x00">
- <documentation>/*! Constant representing command enumeration group
- * in QS_ENUM_DICTIONARY() and QS_ENUM()
- * @sa QS_onCommand()
- */</documentation>
- <code>((uint8_t)7U)</code>
- </attribute>
- <!--${QS-macros::QS_HEX_FMT}-->
- <attribute name="QS_HEX_FMT" type="uint8_t" visibility="0x03" properties="0x00">
- <documentation>/*! Constant representing HEX format for the "width" filed
- * in QS_U8(), QS_U16(), QS_U32(), and QS_U64().
- */</documentation>
- <code>((uint8_t)0x0FU)</code>
- </attribute>
- </package>
- <!--${QS}-->
- <package name="QS" stereotype="0x05">
- <!--${QS::QSCtr}-->
- <attribute name="QSCtr? (QS_CTR_SIZE == 2U)" type="typedef uint_fast16_t" visibility="0x04" properties="0x00">
- <documentation>/*! QS ring buffer counter and offset type */</documentation>
- </attribute>
- <!--${QS::QSCtr}-->
- <attribute name="QSCtr? (QS_CTR_SIZE == 4U)" type="typedef uint_fast32_t" visibility="0x04" properties="0x00"/>
- <!--${QS::QSTimeCtr}-->
- <attribute name="QSTimeCtr? (QS_TIME_SIZE == 4U)" type="typedef uint32_t" visibility="0x04" properties="0x00">
- <documentation>/*! QS time stamp type, which determines the dynamic range of QS time stamps */</documentation>
- </attribute>
- <!--${QS::QSTimeCtr}-->
- <attribute name="QSTimeCtr? (QS_TIME_SIZE == 2U)" type="typedef uint16_t" visibility="0x04" properties="0x00"/>
- <!--${QS::QSTimeCtr}-->
- <attribute name="QSTimeCtr? (QS_TIME_SIZE == 1U)" type="typedef uint8_t" visibility="0x04" properties="0x00"/>
- <!--${QS::QSFun}-->
- <attribute name="QSFun? (QS_FUN_PTR_SIZE == 4U)" type="typedef uint32_t" visibility="0x04" properties="0x00">
- <documentation>/*! QS function pointer type (for serializing function pointers) */</documentation>
- </attribute>
- <!--${QS::QSFun}-->
- <attribute name="QSFun? (QS_FUN_PTR_SIZE == 8U)" type="typedef uint64_t" visibility="0x04" properties="0x00"/>
- <!--${QS::QSFun}-->
- <attribute name="QSFun? (QS_FUN_PTR_SIZE == 2U)" type="typedef uint16_t" visibility="0x04" properties="0x00"/>
- <!--${QS::QSFun}-->
- <attribute name="QSFun? (QS_FUN_PTR_SIZE == 1U)" type="typedef uint8_t" visibility="0x04" properties="0x00"/>
- <!--${QS::QSpyPre}-->
- <attribute name="QSpyPre" type="enum" visibility="0x04" properties="0x00">
- <documentation>/*! QS pre-defined record types (TX channel)
- * @static @public @memberof QS
- *
- * @details
- * This enumeration specifies the record types used in the QP components.
- * You can specify your own record types starting from ::QS_USER offset.
- * Currently, the maximum of all records cannot exceed 125.
- *
- * @note
- * The QS records labeled as "not maskable" are always enabled and cannot
- * be turend off with the QS_GLB_FILTER() macro. Other QS trace records
- * can be disabled by means of the "global filters"
- *
- * @sa QS_GLB_FILTER() macro
- */</documentation>
- <code>{
- /* [0] QS session (not maskable) */
- QS_EMPTY, /*!< QS record for cleanly starting a session */
- /* [1] SM records */
- QS_QEP_STATE_ENTRY, /*!< a state was entered */
- QS_QEP_STATE_EXIT, /*!< a state was exited */
- QS_QEP_STATE_INIT, /*!< an initial transition was taken in a state */
- QS_QEP_INIT_TRAN, /*!< the top-most initial transition was taken */
- QS_QEP_INTERN_TRAN, /*!< an internal transition was taken */
- QS_QEP_TRAN, /*!< a regular transition was taken */
- QS_QEP_IGNORED, /*!< an event was ignored (silently discarded) */
- QS_QEP_DISPATCH, /*!< an event was dispatched (begin of RTC step) */
- QS_QEP_UNHANDLED, /*!< an event was un-handled due to a guard */
- /* [10] Active Object (AO) records */
- QS_QF_ACTIVE_DEFER, /*!< AO deferred an event */
- QS_QF_ACTIVE_RECALL, /*!< AO recalled an event */
- QS_QF_ACTIVE_SUBSCRIBE, /*!< an AO subscribed to an event */
- QS_QF_ACTIVE_UNSUBSCRIBE, /*!< an AO unsubscribed to an event */
- QS_QF_ACTIVE_POST, /*!< an event was posted (FIFO) directly to AO */
- QS_QF_ACTIVE_POST_LIFO, /*!< an event was posted (LIFO) directly to AO */
- QS_QF_ACTIVE_GET, /*!< AO got an event and its queue is not empty */
- QS_QF_ACTIVE_GET_LAST,/*!< AO got an event and its queue is empty */
- QS_QF_ACTIVE_RECALL_ATTEMPT, /*!< AO attempted to recall an event */
- /* [19] Event Queue (EQ) records */
- QS_QF_EQUEUE_POST, /*!< an event was posted (FIFO) to a raw queue */
- QS_QF_EQUEUE_POST_LIFO, /*!< an event was posted (LIFO) to a raw queue */
- QS_QF_EQUEUE_GET, /*!< get an event and queue still not empty */
- QS_QF_EQUEUE_GET_LAST,/*!< get the last event from the queue */
- /* [23] Framework (QF) records */
- QS_QF_NEW_ATTEMPT, /*!< an attempt to allocate an event failed */
- /* [24] Memory Pool (MP) records */
- QS_QF_MPOOL_GET, /*!< a memory block was removed from memory pool */
- QS_QF_MPOOL_PUT, /*!< a memory block was returned to memory pool */
- /* [26] Additional Framework (QF) records */
- QS_QF_PUBLISH, /*!< an event was published to active objects */
- QS_QF_NEW_REF, /*!< new event reference was created */
- QS_QF_NEW, /*!< new event was created */
- QS_QF_GC_ATTEMPT, /*!< garbage collection attempt */
- QS_QF_GC, /*!< garbage collection */
- QS_QF_TICK, /*!< QTimeEvt_tick_() was called */
- /* [32] Time Event (TE) records */
- QS_QF_TIMEEVT_ARM, /*!< a time event was armed */
- QS_QF_TIMEEVT_AUTO_DISARM, /*!< a time event expired and was disarmed */
- QS_QF_TIMEEVT_DISARM_ATTEMPT,/*!< attempt to disarm a disarmed QTimeEvt */
- QS_QF_TIMEEVT_DISARM, /*!< true disarming of an armed time event */
- QS_QF_TIMEEVT_REARM, /*!< rearming of a time event */
- QS_QF_TIMEEVT_POST, /*!< a time event posted itself directly to an AO */
- /* [38] Additional Framework (QF) records */
- QS_QF_DELETE_REF, /*!< an event reference is about to be deleted */
- QS_QF_CRIT_ENTRY, /*!< critical section was entered */
- QS_QF_CRIT_EXIT, /*!< critical section was exited */
- QS_QF_ISR_ENTRY, /*!< an ISR was entered */
- QS_QF_ISR_EXIT, /*!< an ISR was exited */
- QS_QF_INT_DISABLE, /*!< interrupts were disabled */
- QS_QF_INT_ENABLE, /*!< interrupts were enabled */
- /* [45] Additional Active Object (AO) records */
- QS_QF_ACTIVE_POST_ATTEMPT,/*!< attempt to post an evt to AO failed */
- /* [46] Additional Event Queue (EQ) records */
- QS_QF_EQUEUE_POST_ATTEMPT,/*!< attempt to post evt to QEQueue failed */
- /* [47] Additional Memory Pool (MP) records */
- QS_QF_MPOOL_GET_ATTEMPT, /*!< attempt to get a memory block failed */
- /* [48] Scheduler (SC) records */
- QS_SCHED_PREEMPT, /*!< scheduler asynchronously preempted a task */
- QS_SCHED_RESTORE, /*!< scheduler restored preempted task */
- QS_SCHED_LOCK, /*!< scheduler was locked */
- QS_SCHED_UNLOCK, /*!< scheduler was unlocked */
- QS_SCHED_NEXT, /*!< scheduler started new task */
- QS_SCHED_IDLE, /*!< scheduler restored the idle task */
- /* [54] Miscellaneous QS records (not maskable) */
- QS_ENUM_DICT, /*!< enumeration dictionary entry */
- /* [55] Additional QEP records */
- QS_QEP_TRAN_HIST, /*!< a tran to history was taken */
- QS_QEP_TRAN_EP, /*!< a tran to entry point into a submachine */
- QS_QEP_TRAN_XP, /*!< a tran to exit point out of a submachine */
- /* [58] Miscellaneous QS records (not maskable) */
- QS_TEST_PAUSED, /*!< test has been paused */
- QS_TEST_PROBE_GET, /*!< reports that Test-Probe has been used */
- QS_SIG_DICT, /*!< signal dictionary entry */
- QS_OBJ_DICT, /*!< object dictionary entry */
- QS_FUN_DICT, /*!< function dictionary entry */
- QS_USR_DICT, /*!< user QS record dictionary entry */
- QS_TARGET_INFO, /*!< reports the Target information */
- QS_TARGET_DONE, /*!< reports completion of a user callback */
- QS_RX_STATUS, /*!< reports QS data receive status */
- QS_QUERY_DATA, /*!< reports the data from "current object" query */
- QS_PEEK_DATA, /*!< reports the data from the PEEK query */
- QS_ASSERT_FAIL, /*!< assertion failed in the code */
- QS_QF_RUN, /*!< QF_run() was entered */
- /* [71] Semaphore (SEM) records */
- QS_SEM_TAKE, /*!< a semaphore was taken by a thread */
- QS_SEM_BLOCK, /*!< a semaphore blocked a thread */
- QS_SEM_SIGNAL, /*!< a semaphore was signaled */
- QS_SEM_BLOCK_ATTEMPT, /*!< a semaphore blocked was attempted */
- /* [75] Mutex (MTX) records */
- QS_MTX_LOCK, /*!< a mutex was locked */
- QS_MTX_BLOCK, /*!< a mutex blocked a thread */
- QS_MTX_UNLOCK, /*!< a mutex was unlocked */
- QS_MTX_LOCK_ATTEMPT, /*!< a mutex lock was attempted */
- QS_MTX_BLOCK_ATTEMPT, /*!< a mutex blocking was attempted */
- QS_MTX_UNLOCK_ATTEMPT,/*!< a mutex unlock was attempted */
- /* [81] */
- QS_PRE_MAX /*!< the number of predefined signals */
- };</code>
- </attribute>
- <!--${QS::QSpyGroups}-->
- <attribute name="QSpyGroups" type="enum" visibility="0x04" properties="0x00">
- <documentation>/*! QS record groups for QS_GLB_FILTER()
- * @static @public @memberof QS
- */</documentation>
- <code>{
- QS_ALL_RECORDS = 0xF0,/*!< all maskable QS records */
- QS_SM_RECORDS, /*!< State Machine QS records */
- QS_AO_RECORDS, /*!< Active Object QS records */
- QS_EQ_RECORDS, /*!< Event Queues QS records */
- QS_MP_RECORDS, /*!< Memory Pools QS records */
- QS_TE_RECORDS, /*!< Time Events QS records */
- QS_QF_RECORDS, /*!< QF QS records */
- QS_SC_RECORDS, /*!< Scheduler QS records */
- QS_SEM_RECORDS, /*!< Semaphore QS records */
- QS_MTX_RECORDS, /*!< Mutex QS records */
- QS_U0_RECORDS, /*!< User Group 100-104 records */
- QS_U1_RECORDS, /*!< User Group 105-109 records */
- QS_U2_RECORDS, /*!< User Group 110-114 records */
- QS_U3_RECORDS, /*!< User Group 115-119 records */
- QS_U4_RECORDS, /*!< User Group 120-124 records */
- QS_UA_RECORDS /*!< All User records */
- };</code>
- </attribute>
- <!--${QS::QSpyUserOffsets}-->
- <attribute name="QSpyUserOffsets" type="enum" visibility="0x04" properties="0x00">
- <documentation>/*! QS user record group offsets for QS_GLB_FILTER()
- * @static @public @memberof QS
- */</documentation>
- <code>{
- QS_USER = 100, /*!< the first record available to QS users */
- QS_USER0 = (enum_t)QS_USER, /*!< offset for User Group 0 */
- QS_USER1 = (enum_t)QS_USER0 + 5, /*!< offset for User Group 1 */
- QS_USER2 = (enum_t)QS_USER1 + 5, /*!< offset for User Group 2 */
- QS_USER3 = (enum_t)QS_USER2 + 5, /*!< offset for User Group 3 */
- QS_USER4 = (enum_t)QS_USER3 + 5 /*!< offset for User Group 4 */
- };</code>
- </attribute>
- <!--${QS::QSpyIdOffsets}-->
- <attribute name="QSpyIdOffsets" type="enum" visibility="0x04" properties="0x00">
- <documentation>/*! QS ID offsets for QS_LOC_FILTER()
- * @static @public @memberof QS
- */</documentation>
- <code>{
- QS_AO_ID = 0, /*!< offset for AO priorities */
- QS_EP_ID = 64, /*!< offset for event-pool IDs */
- QS_EQ_ID = 80, /*!< offset for event-queue IDs */
- QS_AP_ID = 96 /*!< offset for Application-specific IDs */
- };</code>
- </attribute>
- <!--${QS::QSpyIdGroups}-->
- <attribute name="QSpyIdGroups" type="enum" visibility="0x04" properties="0x00">
- <documentation>/*! QS ID groups for QS_LOC_FILTER()
- * @static @public @memberof QS
- */</documentation>
- <code>{
- QS_ALL_IDS = 0xF0, /*!< all QS IDs */
- QS_AO_IDS = (0x80 + (enum_t)QS_AO_ID), /*!< AO IDs (priorities) */
- QS_EP_IDS = (0x80 + (enum_t)QS_EP_ID), /*!< event-pool IDs */
- QS_EQ_IDS = (0x80 + (enum_t)QS_EQ_ID), /*!< event-queue IDs */
- QS_AP_IDS = (0x80 + (enum_t)QS_AP_ID) /*!< Application-specific IDs */
- };</code>
- </attribute>
- <!--${QS::QSpyFunPtr}-->
- <attribute name="QSpyFunPtr" type="typedef void (*" visibility="0x04" properties="0x01">
- <documentation>/*! function pointer type for QS_fun_dict_pre_()
- * @static @private @memberof QS
- */</documentation>
- <code>)(void);</code>
- </attribute>
- <!--${QS::QSpyId}-->
- <attribute name="QSpyId" type="typedef struct { uint8_t prio; }" visibility="0x04" properties="0x00">
- <documentation>/*! @brief QS ID type for applying local filtering
- * @static @public @memberof QS
- */</documentation>
- </attribute>
- <!--${QS::QS-tx}-->
- <package name="QS-tx" stereotype="0x02" namespace="QS_">
- <!--${QS::QS-tx::tx}-->
- <class name="tx">
- <documentation>/*! @brief Software tracing, output (QS-TX)
- * @class QS
- *
- * @details
- * This class groups together QS services.
- */</documentation>
- <!--${QS::QS-tx::tx::glbFilter[16]}-->
- <attribute name="glbFilter[16]" type="uint8_t" visibility="0x00" properties="0x00">
- <documentation>/*! global on/off QS filter */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::locFilter[16]}-->
- <attribute name="locFilter[16]" type="uint8_t" visibility="0x00" properties="0x00">
- <documentation>/*! local on/off QS filter */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::locFilter_AP}-->
- <attribute name="locFilter_AP" type="void const *" visibility="0x00" properties="0x00">
- <documentation>/*! @deprecated old local QS filter */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::buf}-->
- <attribute name="buf" type="uint8_t *" visibility="0x00" properties="0x00">
- <documentation>/*! pointer to the start of the QS-TX ring buffer */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::end}-->
- <attribute name="end" type="QSCtr" visibility="0x00" properties="0x00">
- <documentation>/*! offset of the end of the ring buffer */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::head}-->
- <attribute name="head" type="QSCtr volatile" visibility="0x00" properties="0x00">
- <documentation>/*! offset to where next byte will be inserted */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::tail}-->
- <attribute name="tail" type="QSCtr volatile" visibility="0x00" properties="0x00">
- <documentation>/*! offset of where next record will be extracted */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::used}-->
- <attribute name="used" type="QSCtr volatile" visibility="0x00" properties="0x00">
- <documentation>/*! number of bytes currently in the ring buffer */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::seq}-->
- <attribute name="seq" type="uint8_t volatile" visibility="0x00" properties="0x00">
- <documentation>/*! sequence number of the last inserted QS record */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::chksum}-->
- <attribute name="chksum" type="uint8_t volatile" visibility="0x00" properties="0x00">
- <documentation>/*! checksum of the currently inserted record */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::critNest}-->
- <attribute name="critNest" type="uint8_t volatile" visibility="0x00" properties="0x00">
- <documentation>/*! critical section nesting level */</documentation>
- </attribute>
- <!--${QS::QS-tx::tx::flags}-->
- <attribute name="flags" type="uint8_t" visibility="0x00" properties="0x00">
- <documentation>/* flags for internal use */</documentation>
- </attribute>
- </class>
- <!--${QS::QS-tx::preType}-->
- <attribute name="preType" type="enum" visibility="0x04" properties="0x01">
- <documentation>/*! Enumerates data elements for app-specific trace records */</documentation>
- <code>{
- QS_I8_ENUM_T, /*!< signed 8-bit integer or enum format */
- QS_U8_T, /*!< unsigned 8-bit integer format */
- QS_I16_T, /*!< signed 16-bit integer format */
- QS_U16_T, /*!< unsigned 16-bit integer format */
- QS_I32_T, /*!< signed 32-bit integer format */
- QS_U32_T, /*!< unsigned 32-bit integer format */
- QS_F32_T, /*!< 32-bit floating point format */
- QS_F64_T, /*!< 64-bit floating point format */
- QS_STR_T, /*!< zero-terminated ASCII string format */
- QS_MEM_T, /*!< up to 255-bytes memory block format */
- QS_SIG_T, /*!< event signal format */
- QS_OBJ_T, /*!< object pointer format */
- QS_FUN_T, /*!< function pointer format */
- QS_I64_T, /*!< signed 64-bit integer format */
- QS_U64_T /*!< unsigned 64-bit integer format */
- };</code>
- </attribute>
- <!--${QS::QS-tx::priv_}-->
- <attribute name="priv_" type="QS_tx" visibility="0x00" properties="0x01">
- <documentation>/*! the only instance of the QS-TX object (Singleton) */</documentation>
- </attribute>
- <!--${QS::QS-tx::initBuf}-->
- <operation name="initBuf" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Initialize the QS-TX data buffer
- * @static @public @memberof QS_tx
- *
- * @details
- * This function should be called from QS_onStartup() to provide
- * QS with the data buffer. The first argument `sto` is the address
- * of the memory block, and the second argument `stoSize` is the size
- * of this block [in bytes]. Currently the size of the QS buffer cannot
- * exceed 64KB.
- *
- * @param[in] sto pointer to the storage for the transmit buffer
- * @param[in] stoSize size in [bytes] of the storage buffer
- *
- * @remark
- * QS can work with quite small data buffers, but you will start losing
- * data if the buffer is too small for the bursts of tracing activity.
- * The right size of the buffer depends on the data production rate and
- * the data output rate. QS offers flexible filtering to reduce the data
- * production rate.
- *
- * @note
- * If the data output rate cannot keep up with the production rate,
- * QS will start overwriting the older data with newer data. This is
- * consistent with the "last-is-best" QS policy. The record sequence
- * counters and check sums on each record allow the QSPY host utility
- * to easily detect any data loss.
- */
- /*! @static @public @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::initBuf::sto}-->
- <parameter name="sto" type="uint8_t * const"/>
- <!--${QS::QS-tx::initBuf::stoSize}-->
- <parameter name="stoSize" type="uint_fast32_t const"/>
- <code>/* the provided buffer must be at least 8 bytes long */
- Q_REQUIRE_ID(100, stoSize > 8U);
- QS_priv_.buf = &sto[0];
- QS_priv_.end = (QSCtr)stoSize;
- QS_priv_.head = 0U;
- QS_priv_.tail = 0U;
- QS_priv_.used = 0U;
- QS_priv_.seq = 0U;
- QS_priv_.chksum = 0U;
- QS_priv_.critNest = 0U;
- QS_glbFilter_(-(int_fast16_t)QS_ALL_RECORDS); /* all global filters OFF */
- QS_locFilter_((int_fast16_t)QS_ALL_IDS); /* all local filters ON */
- QS_priv_.locFilter_AP = (void *)0; /* deprecated "AP-filter" */
- /* produce an empty record to "flush" the QS trace buffer */
- QS_beginRec_((uint_fast8_t)QS_EMPTY);
- QS_endRec_();
- /* produce the reset record to inform QSPY of a new session */
- QS_target_info_pre_(0xFFU); /* send Reset and Target info */
- /* hold off flushing after successfull initialization (see QS_INIT()) */</code>
- </operation>
- <!--${QS::QS-tx::getByte}-->
- <operation name="getByte" type="uint16_t" visibility="0x00" properties="0x00">
- <documentation>/*! Byte-oriented interface to the QS-TX data buffer
- * @static @public @memberof QS_tx
- *
- * @details
- * This function delivers one byte at a time from the QS data buffer.
- *
- * @returns
- * the byte in the least-significant 8-bits of the 16-bit return
- * value if the byte is available. If no more data is available at the
- * time, the function returns ::QS_EOD (End-Of-Data).
- *
- * @note
- * QS_getByte() is NOT protected with a critical section.
- */
- /*! @static @public @memberof QS_tx */</documentation>
- <code>uint16_t ret;
- if (QS_priv_.used == 0U) {
- ret = QS_EOD; /* set End-Of-Data */
- }
- else {
- uint8_t const * const buf = QS_priv_.buf; /* put in a temporary */
- QSCtr tail = QS_priv_.tail; /* put in a temporary (register) */
- ret = (uint16_t)buf[tail]; /* set the byte to return */
- ++tail; /* advance the tail */
- if (tail == QS_priv_.end) { /* tail wrap around? */
- tail = 0U;
- }
- QS_priv_.tail = tail; /* update the tail */
- --QS_priv_.used; /* one less byte used */
- }
- return ret; /* return the byte or EOD */</code>
- </operation>
- <!--${QS::QS-tx::getBlock}-->
- <operation name="getBlock" type="uint8_t const *" visibility="0x00" properties="0x00">
- <documentation>/*! Block-oriented interface to the QS-TX data buffer
- * @static @public @memberof QS_tx
- *
- * @details
- * This function delivers a contiguous block of data from the QS data
- * buffer. The function returns the pointer to the beginning of the
- * block, and writes the number of bytes in the block to the location
- * pointed to by `pNbytes`. The argument `pNbytes` is also used as
- * input to provide the maximum size of the data block that the caller
- * can accept.
- *
- * @param[in,out] pNbytes pointer to the number of bytes to send.
- * On input, `pNbytes` specifies the maximum number
- * of bytes that the function can provide.
- * On output, `pNbytes` contains the actual number
- * of bytes available.
- * @returns
- * if data is available, the function returns pointer to the
- * contiguous block of data and sets the value pointed to by `pNbytes`
- * to the # available bytes. If data is available at the time the
- * function is called, the function returns NULL pointer and sets the
- * value pointed to by `pNbytes` to zero.
- *
- * @note
- * Only the NULL return from QS_getBlock() indicates that the QS
- * buffer is empty at the time of the call. The non-NULL return often
- * means that the block is at the end of the buffer and you need to call
- * QS_getBlock() again to obtain the rest of the data that
- * "wrapped around" to the beginning of the QS data buffer.
- *
- * @note QS_getBlock() is **not** protected with a critical section.
- */
- /*! @static @public @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::getBlock::pNbytes}-->
- <parameter name="pNbytes" type="uint16_t * const"/>
- <code>QSCtr const used = QS_priv_.used; /* put in a temporary (register) */
- uint8_t const *buf;
- /* any bytes used in the ring buffer? */
- if (used != 0U) {
- QSCtr tail = QS_priv_.tail; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- QSCtr n = (QSCtr)(end - tail);
- if (n > used) {
- n = used;
- }
- if (n > (QSCtr)(*pNbytes)) {
- n = (QSCtr)(*pNbytes);
- }
- *pNbytes = (uint16_t)n; /* n-bytes available */
- buf = &QS_priv_.buf[tail]; /* the bytes are at the tail */
- QS_priv_.used = (QSCtr)(used - n);
- tail += n;
- if (tail == end) {
- tail = 0U;
- }
- QS_priv_.tail = tail;
- }
- else { /* no bytes available */
- *pNbytes = 0U; /* no bytes available right now */
- buf = (uint8_t *)0; /* no bytes available right now */
- }
- return buf;</code>
- </operation>
- <!--${QS::QS-tx::glbFilter_}-->
- <operation name="glbFilter_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Set/clear the global Filter for a given QS record or a group
- * of records
- * @static @public @memberof QS_tx
- *
- * @details
- * This function sets up the QS filter to enable record types specified
- * in the `filter` parameter. The value #QS_ALL_RECORDS specifies to
- * filter-in all records. This function should be called indirectly
- * through the macro QS_GLB_FILTER()
- *
- * @param[in] filter the QS record-d or group to enable in the filter,
- * if positive or disable, if negative. The record-id
- * numbers must be in the range -127..127.
- * @note
- * Filtering based on the record-type is only the first layer of
- * filtering. The second layer is based on the object-type. Both filter
- * layers must be enabled for the QS record to be inserted in the
- * QS buffer.
- *
- * @sa QS_locFilter_()
- */
- /*! @static @public @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::glbFilter_::filter}-->
- <parameter name="filter" type="int_fast16_t const"/>
- <code>bool const isRemove = (filter < 0);
- uint8_t const rec = isRemove ? (uint8_t)(-filter) : (uint8_t)filter;
- switch (rec) {
- case (uint8_t)QS_ALL_RECORDS: {
- uint8_t const tmp = (isRemove ? 0x00U : 0xFFU);
- /* set all global filters (partially unrolled loop) */
- for (uint_fast8_t i = 0U;
- i < Q_DIM(QS_priv_.glbFilter);
- i += 4U)
- {
- QS_priv_.glbFilter[i ] = tmp;
- QS_priv_.glbFilter[i + 1U] = tmp;
- QS_priv_.glbFilter[i + 2U] = tmp;
- QS_priv_.glbFilter[i + 3U] = tmp;
- }
- if (isRemove) {
- /* leave the "not maskable" filters enabled,
- * see qs.h, Miscellaneous QS records (not maskable)
- */
- QS_priv_.glbFilter[0] = 0x01U;
- QS_priv_.glbFilter[6] = 0x40U;
- QS_priv_.glbFilter[7] = 0xFCU;
- QS_priv_.glbFilter[8] = 0x7FU;
- }
- else {
- /* never turn the last 3 records on (0x7D, 0x7E, 0x7F) */
- QS_priv_.glbFilter[15] = 0x1FU;
- }
- break;
- }
- case (uint8_t)QS_SM_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[0] &= (uint8_t)(~0xFEU & 0xFFU);
- QS_priv_.glbFilter[1] &= (uint8_t)(~0x03U & 0xFFU);
- QS_priv_.glbFilter[6] &= (uint8_t)(~0x80U & 0xFFU);
- QS_priv_.glbFilter[7] &= (uint8_t)(~0x03U & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[0] |= 0xFEU;
- QS_priv_.glbFilter[1] |= 0x03U;
- QS_priv_.glbFilter[6] |= 0x80U;
- QS_priv_.glbFilter[7] |= 0x03U;
- }
- break;
- case (uint8_t)QS_AO_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[1] &= (uint8_t)(~0xFCU & 0xFFU);
- QS_priv_.glbFilter[2] &= (uint8_t)(~0x07U & 0xFFU);
- QS_priv_.glbFilter[5] &= (uint8_t)(~0x20U & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[1] |= 0xFCU;
- QS_priv_.glbFilter[2] |= 0x07U;
- QS_priv_.glbFilter[5] |= 0x20U;
- }
- break;
- case (uint8_t)QS_EQ_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[2] &= (uint8_t)(~0x78U & 0xFFU);
- QS_priv_.glbFilter[5] &= (uint8_t)(~0x40U & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[2] |= 0x78U;
- QS_priv_.glbFilter[5] |= 0x40U;
- }
- break;
- case (uint8_t)QS_MP_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[3] &= (uint8_t)(~0x03U & 0xFFU);
- QS_priv_.glbFilter[5] &= (uint8_t)(~0x80U & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[3] |= 0x03U;
- QS_priv_.glbFilter[5] |= 0x80U;
- }
- break;
- case (uint8_t)QS_QF_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[2] &= (uint8_t)(~0x80U & 0xFFU);
- QS_priv_.glbFilter[3] &= (uint8_t)(~0xFCU & 0xFFU);
- QS_priv_.glbFilter[4] &= (uint8_t)(~0xC0U & 0xFFU);
- QS_priv_.glbFilter[5] &= (uint8_t)(~0x1FU & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[2] |= 0x80U;
- QS_priv_.glbFilter[3] |= 0xFCU;
- QS_priv_.glbFilter[4] |= 0xC0U;
- QS_priv_.glbFilter[5] |= 0x1FU;
- }
- break;
- case (uint8_t)QS_TE_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[4] &= (uint8_t)(~0x3FU & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[4] |= 0x3FU;
- }
- break;
- case (uint8_t)QS_SC_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[6] &= (uint8_t)(~0x3FU & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[6] |= 0x3FU;
- }
- break;
- case (uint8_t)QS_SEM_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[8] &= (uint8_t)(~0x80U & 0xFFU);
- QS_priv_.glbFilter[9] &= (uint8_t)(~0x07U & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[8] |= 0x80U;
- QS_priv_.glbFilter[9] |= 0x07U;
- }
- break;
- case (uint8_t)QS_MTX_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[9] &= (uint8_t)(~0xF8U & 0xFFU);
- QS_priv_.glbFilter[10] &= (uint8_t)(~0x01U & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[9] |= 0xF8U;
- QS_priv_.glbFilter[10] |= 0x01U;
- }
- break;
- case (uint8_t)QS_U0_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[12] &= (uint8_t)(~0xF0U & 0xFFU);
- QS_priv_.glbFilter[13] &= (uint8_t)(~0x01U & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[12] |= 0xF0U;
- QS_priv_.glbFilter[13] |= 0x01U;
- }
- break;
- case (uint8_t)QS_U1_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[13] &= (uint8_t)(~0x3EU & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[13] |= 0x3EU;
- }
- break;
- case (uint8_t)QS_U2_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[13] &= (uint8_t)(~0xC0U & 0xFFU);
- QS_priv_.glbFilter[14] &= (uint8_t)(~0x07U & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[13] |= 0xC0U;
- QS_priv_.glbFilter[14] |= 0x07U;
- }
- break;
- case (uint8_t)QS_U3_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[14] &= (uint8_t)(~0xF8U & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[14] |= 0xF8U;
- }
- break;
- case (uint8_t)QS_U4_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[15] &= 0x1FU;
- }
- else {
- QS_priv_.glbFilter[15] |= 0x1FU;
- }
- break;
- case (uint8_t)QS_UA_RECORDS:
- if (isRemove) {
- QS_priv_.glbFilter[12] &= (uint8_t)(~0xF0U & 0xFFU);
- QS_priv_.glbFilter[13] = 0U;
- QS_priv_.glbFilter[14] = 0U;
- QS_priv_.glbFilter[15] &= (uint8_t)(~0x1FU & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[12] |= 0xF0U;
- QS_priv_.glbFilter[13] |= 0xFFU;
- QS_priv_.glbFilter[14] |= 0xFFU;
- QS_priv_.glbFilter[15] |= 0x1FU;
- }
- break;
- default:
- /* QS rec number can't exceed 0x7D, so no need for escaping */
- Q_ASSERT_ID(210, rec < 0x7DU);
- if (isRemove) {
- QS_priv_.glbFilter[rec >> 3U]
- &= (uint8_t)(~(1U << (rec & 7U)) & 0xFFU);
- }
- else {
- QS_priv_.glbFilter[rec >> 3U]
- |= (1U << (rec & 7U));
- /* never turn the last 3 records on (0x7D, 0x7E, 0x7F) */
- QS_priv_.glbFilter[15] &= 0x1FU;
- }
- break;
- }</code>
- </operation>
- <!--${QS::QS-tx::locFilter_}-->
- <operation name="locFilter_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Set/clear the local Filter for a given object-id
- * or a group of object-ids
- * @static @public @memberof QS_tx
- *
- * @details
- * This function sets up the local QS filter to enable or disable the
- * given QS object-id or a group of object-ids @a filter.
- * This function should be called indirectly through the macro
- * QS_LOC_FILTER()
- *
- * @param[in] filter the QS object-id or group to enable in the filter,
- * if positive or disable, if negative. The qs_id numbers
- * must be in the range 1..127.
- * @note
- * Filtering based on the object-id (local filter) is the second layer
- * of filtering. The first layer is based on the QS record-type (global
- * filter). Both filter layers must be enabled for the QS record to be
- * inserted into the QS buffer.
- *
- * @sa QS_glbFilter_()
- */
- /*! @static @public @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::locFilter_::filter}-->
- <parameter name="filter" type="int_fast16_t const"/>
- <code>bool const isRemove = (filter < 0);
- uint8_t const qs_id = isRemove ? (uint8_t)(-filter) : (uint8_t)filter;
- uint8_t const tmp = (isRemove ? 0x00U : 0xFFU);
- uint_fast8_t i;
- switch (qs_id) {
- case (uint8_t)QS_ALL_IDS:
- /* set all local filters (partially unrolled loop) */
- for (i = 0U; i < Q_DIM(QS_priv_.locFilter); i += 4U) {
- QS_priv_.locFilter[i ] = tmp;
- QS_priv_.locFilter[i + 1U] = tmp;
- QS_priv_.locFilter[i + 2U] = tmp;
- QS_priv_.locFilter[i + 3U] = tmp;
- }
- break;
- case (uint8_t)QS_AO_IDS:
- for (i = 0U; i < 8U; i += 4U) {
- QS_priv_.locFilter[i ] = tmp;
- QS_priv_.locFilter[i + 1U] = tmp;
- QS_priv_.locFilter[i + 2U] = tmp;
- QS_priv_.locFilter[i + 3U] = tmp;
- }
- break;
- case (uint8_t)QS_EP_IDS:
- i = 8U;
- QS_priv_.locFilter[i ] = tmp;
- QS_priv_.locFilter[i + 1U] = tmp;
- break;
- case (uint8_t)QS_AP_IDS:
- i = 12U;
- QS_priv_.locFilter[i ] = tmp;
- QS_priv_.locFilter[i + 1U] = tmp;
- QS_priv_.locFilter[i + 2U] = tmp;
- QS_priv_.locFilter[i + 3U] = tmp;
- break;
- default:
- if (qs_id < 0x7FU) {
- if (isRemove) {
- QS_priv_.locFilter[qs_id >> 3U]
- &= (uint8_t)(~(1U << (qs_id & 7U)) & 0xFFU);
- }
- else {
- QS_priv_.locFilter[qs_id >> 3U]
- |= (1U << (qs_id & 7U));
- }
- }
- else {
- Q_ERROR_ID(310); /* incorrect qs_id */
- }
- break;
- }
- QS_priv_.locFilter[0] |= 0x01U; /* leave QS_ID == 0 always on */</code>
- </operation>
- <!--${QS::QS-tx::doOutput}-->
- <operation name="doOutput" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Perform the QS-TX output (implemented in some QS ports)
- * @static @public @memberof QS_tx
- */
- /*! @static @public @memberof QS_tx */</documentation>
- </operation>
- <!--${QS::QS-tx::beginRec_}-->
- <operation name="beginRec_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Mark the begin of a QS record `rec`
- * @static @private @memberof QS_tx
- *
- * @details
- * This function must be called at the beginning of each QS record.
- * This function should be called indirectly through the macro QS_BEGIN_ID(),
- * or QS_BEGIN_NOCRIT(), depending if it's called in a normal code or from
- * a critical section.
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::beginRec_::rec}-->
- <parameter name="rec" type="uint_fast8_t const"/>
- <code>uint8_t const b = (uint8_t)(QS_priv_.seq + 1U);
- uint8_t chksum = 0U; /* reset the checksum */
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.seq = b; /* store the incremented sequence num */
- QS_priv_.used += 2U; /* 2 bytes about to be added */
- QS_INSERT_ESC_BYTE_(b)
- chksum = (uint8_t)(chksum + rec); /* update checksum */
- QS_INSERT_BYTE_((uint8_t)rec) /* rec byte does not need escaping */
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx::endRec_}-->
- <operation name="endRec_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Mark the end of a QS record `rec`
- * @static @private @memberof QS_tx
- *
- * @details
- * This function must be called at the end of each QS record.
- * This function should be called indirectly through the macro QS_END(),
- * or QS_END_NOCRIT(), depending if it's called in a normal code or from
- * a critical section.
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <code>uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head;
- QSCtr const end = QS_priv_.end;
- uint8_t b = QS_priv_.chksum;
- b ^= 0xFFU; /* invert the bits in the checksum */
- QS_priv_.used += 2U; /* 2 bytes about to be added */
- if ((b != QS_FRAME) && (b != QS_ESC)) {
- QS_INSERT_BYTE_(b)
- }
- else {
- QS_INSERT_BYTE_(QS_ESC)
- QS_INSERT_BYTE_(b ^ QS_ESC_XOR)
- ++QS_priv_.used; /* account for the ESC byte */
- }
- QS_INSERT_BYTE_(QS_FRAME) /* do not escape this QS_FRAME */
- QS_priv_.head = head; /* save the head */
- /* overrun over the old data? */
- if (QS_priv_.used > end) {
- QS_priv_.used = end; /* the whole buffer is used */
- QS_priv_.tail = head; /* shift the tail to the old data */
- }</code>
- </operation>
- <!--${QS::QS-tx::u8_raw_}-->
- <operation name="u8_raw_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! output uint8_t data element without format information
- * @static @private @memberof QS_tx
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::u8_raw_::d}-->
- <parameter name="d" type="uint8_t const"/>
- <code>uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.used += 1U; /* 1 byte about to be added */
- QS_INSERT_ESC_BYTE_(d)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx::2u8_raw_}-->
- <operation name="2u8_raw_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! output two uint8_t data elements without format information
- * @static @private @memberof QS_tx
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::2u8_raw_::d1}-->
- <parameter name="d1" type="uint8_t const"/>
- <!--${QS::QS-tx::2u8_raw_::d2}-->
- <parameter name="d2" type="uint8_t const"/>
- <code>uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.used += 2U; /* 2 bytes are about to be added */
- QS_INSERT_ESC_BYTE_(d1)
- QS_INSERT_ESC_BYTE_(d2)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx::u16_raw_}-->
- <operation name="u16_raw_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! output uint16_t data element without format information
- * @static @private @memberof QS_tx
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::u16_raw_::d}-->
- <parameter name="d" type="uint16_t const"/>
- <code>uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- uint16_t x = d;
- QS_priv_.used += 2U; /* 2 bytes are about to be added */
- QS_INSERT_ESC_BYTE_((uint8_t)x)
- x >>= 8U;
- QS_INSERT_ESC_BYTE_((uint8_t)x)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx::u32_raw_}-->
- <operation name="u32_raw_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! output uint32_t data element without format information
- * @static @private @memberof QS_tx
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::u32_raw_::d}-->
- <parameter name="d" type="uint32_t const"/>
- <code>uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- uint32_t x = d;
- QS_priv_.used += 4U; /* 4 bytes are about to be added */
- for (uint_fast8_t i = 4U; i != 0U; --i) {
- QS_INSERT_ESC_BYTE_((uint8_t)x)
- x >>= 8U;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx::obj_raw_}-->
- <operation name="obj_raw_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output obj pointer data element without format information
- * @static @private @memberof QS_tx
- *
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::obj_raw_::obj}-->
- <parameter name="obj" type="void const * const"/>
- <code>#if (QS_OBJ_PTR_SIZE == 1U)
- QS_u8_raw_((uint8_t)obj);
- #elif (QS_OBJ_PTR_SIZE == 2U)
- QS_u16_raw_((uint16_t)obj);
- #elif (QS_OBJ_PTR_SIZE == 4U)
- QS_u32_raw_((uint32_t)obj);
- #elif (QS_OBJ_PTR_SIZE == 8U)
- QS_u64_raw_((uint64_t)obj);
- #else
- QS_u32_raw_((uint32_t)obj);
- #endif</code>
- </operation>
- <!--${QS::QS-tx::str_raw_}-->
- <operation name="str_raw_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output raw zero-terminated string element (without format information)
- * @static @private @memberof QS_tx
- *
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::str_raw_::str}-->
- <parameter name="str" type="char const * const"/>
- <code>uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- QSCtr used = QS_priv_.used; /* put in a temporary (register) */
- for (char const *s = str; *s != '\0'; ++s) {
- chksum += (uint8_t)*s; /* update checksum */
- QS_INSERT_BYTE_((uint8_t)*s) /* ASCII char doesn't need escaping */
- ++used;
- }
- QS_INSERT_BYTE_((uint8_t)'\0') /* zero-terminate the string */
- ++used;
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- QS_priv_.used = used; /* save # of used buffer space */</code>
- </operation>
- <!--${QS::QS-tx::u8_fmt_}-->
- <operation name="u8_fmt_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output uint8_t data element with format information
- * @static @private @memberof QS_tx
- *
- * @details
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::u8_fmt_::format}-->
- <parameter name="format" type="uint8_t const"/>
- <!--${QS::QS-tx::u8_fmt_::d}-->
- <parameter name="d" type="uint8_t const"/>
- <code>uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- QS_priv_.used += 2U; /* 2 bytes about to be added */
- QS_INSERT_ESC_BYTE_(format)
- QS_INSERT_ESC_BYTE_(d)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx::u16_fmt_}-->
- <operation name="u16_fmt_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! output uint16_t data element with format information
- * @static @private @memberof QS_tx
- *
- * @details
- * This function is only to be used through macros, never in the
- * client code directly.
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::u16_fmt_::format}-->
- <parameter name="format" type="uint8_t const"/>
- <!--${QS::QS-tx::u16_fmt_::d}-->
- <parameter name="d" type="uint16_t const"/>
- <code>uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- uint8_t b = (uint8_t)d;
- QS_priv_.used += 3U; /* 3 bytes about to be added */
- QS_INSERT_ESC_BYTE_(format)
- QS_INSERT_ESC_BYTE_(b)
- b = (uint8_t)(d >> 8U);
- QS_INSERT_ESC_BYTE_(b)
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx::u32_fmt_}-->
- <operation name="u32_fmt_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output uint32_t data element with format information
- * @static @private @memberof QS_tx
- *
- * @note This function is only to be used through macros, never in the
- * client code directly.
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::u32_fmt_::format}-->
- <parameter name="format" type="uint8_t const"/>
- <!--${QS::QS-tx::u32_fmt_::d}-->
- <parameter name="d" type="uint32_t const"/>
- <code>uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- uint32_t x = d;
- QS_priv_.used += 5U; /* 5 bytes about to be added */
- QS_INSERT_ESC_BYTE_(format) /* insert the format byte */
- /* insert 4 bytes... */
- for (uint_fast8_t i = 4U; i != 0U; --i) {
- QS_INSERT_ESC_BYTE_((uint8_t)x)
- x >>= 8U;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx::str_fmt_}-->
- <operation name="str_fmt_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output formatted zero-terminated ASCII string to the QS record
- * @static @private @memberof QS_tx
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::str_fmt_::str}-->
- <parameter name="str" type="char const * const"/>
- <code>uint8_t chksum = QS_priv_.chksum;
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- QSCtr used = QS_priv_.used; /* put in a temporary (register) */
- used += 2U; /* account for the format byte and the terminating-0 */
- QS_INSERT_BYTE_((uint8_t)QS_STR_T)
- chksum += (uint8_t)QS_STR_T;
- for (char const *s = str; *s != '\0'; ++s) {
- QS_INSERT_BYTE_((uint8_t)*s) /* ASCII char doesn't need escaping */
- chksum += (uint8_t)*s; /* update checksum */
- ++used;
- }
- QS_INSERT_BYTE_(0U) /* zero-terminate the string */
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */
- QS_priv_.used = used; /* save # of used buffer space */</code>
- </operation>
- <!--${QS::QS-tx::mem_fmt_}-->
- <operation name="mem_fmt_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output formatted memory block of up to 255 bytes to the QS record
- * @static @private @memberof QS_tx
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::mem_fmt_::blk}-->
- <parameter name="blk" type="uint8_t const * const"/>
- <!--${QS::QS-tx::mem_fmt_::size}-->
- <parameter name="size" type="uint8_t const"/>
- <code>uint8_t chksum = QS_priv_.chksum;
- uint8_t * const buf = QS_priv_.buf; /* put in a temporary (register) */
- QSCtr head = QS_priv_.head; /* put in a temporary (register) */
- QSCtr const end = QS_priv_.end; /* put in a temporary (register) */
- uint8_t const *pb = blk;
- QS_priv_.used += ((QSCtr)size + 2U); /* size+2 bytes to be added */
- QS_INSERT_BYTE_((uint8_t)QS_MEM_T)
- chksum += (uint8_t)QS_MEM_T;
- QS_INSERT_ESC_BYTE_(size)
- /* output the 'size' number of bytes */
- for (uint8_t len = size; len > 0U; --len) {
- QS_INSERT_ESC_BYTE_(*pb)
- ++pb;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx::sig_dict_pre_}-->
- <operation name="sig_dict_pre_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output predefined signal-dictionary record
- * @static @private @memberof QS_tx
- *
- * @note This function is only to be used through macro QS_SIG_DICTIONARY()
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::sig_dict_pre_::sig}-->
- <parameter name="sig" type="enum_t const"/>
- <!--${QS::QS-tx::sig_dict_pre_::obj}-->
- <parameter name="obj" type="void const * const"/>
- <!--${QS::QS-tx::sig_dict_pre_::name}-->
- <parameter name="name" type="char const * const"/>
- <code>QS_CRIT_STAT_
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_SIG_DICT);
- QS_SIG_PRE_(sig);
- QS_OBJ_PRE_(obj);
- QS_str_raw_((*name == '&') ? &name[1] : name);
- QS_endRec_();
- QS_CRIT_X_();
- QS_onFlush();</code>
- </operation>
- <!--${QS::QS-tx::obj_dict_pre_}-->
- <operation name="obj_dict_pre_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output predefined object-dictionary record
- * @static @private @memberof QS_tx
- *
- * @note This function is only to be used through macro QS_OBJ_DICTIONARY()
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::obj_dict_pre_::obj}-->
- <parameter name="obj" type="void const * const"/>
- <!--${QS::QS-tx::obj_dict_pre_::name}-->
- <parameter name="name" type="char const * const"/>
- <code>QS_CRIT_STAT_
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_OBJ_DICT);
- QS_OBJ_PRE_(obj);
- QS_str_raw_((*name == '&') ? &name[1] : name);
- QS_endRec_();
- QS_CRIT_X_();
- QS_onFlush();</code>
- </operation>
- <!--${QS::QS-tx::obj_arr_dict_pre_}-->
- <operation name="obj_arr_dict_pre_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output predefined object-array dictionary record
- * @static @private @memberof QS_tx
- *
- * @note This function is only to be used through macro QS_OBJ_ARR_DICTIONARY()
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::obj_arr_dict_pre~::obj}-->
- <parameter name="obj" type="void const * const"/>
- <!--${QS::QS-tx::obj_arr_dict_pre~::idx}-->
- <parameter name="idx" type="uint_fast16_t const"/>
- <!--${QS::QS-tx::obj_arr_dict_pre~::name}-->
- <parameter name="name" type="char const * const"/>
- <code>Q_REQUIRE_ID(400, idx < 1000U);
- /* format idx into a char buffer as "xxx\0" */
- uint8_t idx_str[4];
- uint_fast16_t tmp = idx;
- uint8_t i;
- idx_str[3] = 0U; /* zero-terminate */
- idx_str[2] = (uint8_t)((uint8_t)'0' + (tmp % 10U));
- tmp /= 10U;
- idx_str[1] = (uint8_t)((uint8_t)'0' + (tmp % 10U));
- if (idx_str[1] == (uint8_t)'0') {
- i = 2U;
- }
- else {
- tmp /= 10U;
- idx_str[0] = (uint8_t)((uint8_t)'0' + (tmp % 10U));
- if (idx_str[0] == (uint8_t)'0') {
- i = 1U;
- }
- else {
- i = 0U;
- }
- }
- QS_CRIT_STAT_
- uint8_t j = ((*name == '&') ? 1U : 0U);
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_OBJ_DICT);
- QS_OBJ_PRE_(obj);
- for (; name[j] != '\0'; ++j) {
- QS_U8_PRE_(name[j]);
- if (name[j] == '[') {
- ++j;
- break;
- }
- }
- for (; idx_str[i] != 0U; ++i) {
- QS_U8_PRE_(idx_str[i]);
- }
- /* skip chars until ']' */
- for (; name[j] != '\0'; ++j) {
- if (name[j] == ']') {
- break;
- }
- }
- for (; name[j] != '\0'; ++j) {
- QS_U8_PRE_(name[j]);
- }
- QS_U8_PRE_(0U); /* zero-terminate */
- QS_endRec_();
- QS_CRIT_X_();
- QS_onFlush();</code>
- </operation>
- <!--${QS::QS-tx::fun_dict_pre_}-->
- <operation name="fun_dict_pre_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output predefined function-dictionary record
- * @static @private @memberof QS_tx
- *
- * @note This function is only to be used through macro QS_FUN_DICTIONARY()
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::fun_dict_pre_::fun}-->
- <parameter name="fun" type="QSpyFunPtr const"/>
- <!--${QS::QS-tx::fun_dict_pre_::name}-->
- <parameter name="name" type="char const * const"/>
- <code>QS_CRIT_STAT_
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_FUN_DICT);
- QS_FUN_PRE_(fun);
- QS_str_raw_((*name == '&') ? &name[1] : name);
- QS_endRec_();
- QS_CRIT_X_();
- QS_onFlush();</code>
- </operation>
- <!--${QS::QS-tx::usr_dict_pre_}-->
- <operation name="usr_dict_pre_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output predefined user-dictionary record
- * @static @private @memberof QS_tx
- *
- * @note This function is only to be used through macro QS_USR_DICTIONARY()
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::usr_dict_pre_::rec}-->
- <parameter name="rec" type="enum_t const"/>
- <!--${QS::QS-tx::usr_dict_pre_::name}-->
- <parameter name="name" type="char const * const"/>
- <code>QS_CRIT_STAT_
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_USR_DICT);
- QS_u8_raw_((uint8_t)rec);
- QS_str_raw_(name);
- QS_endRec_();
- QS_CRIT_X_();
- QS_onFlush();</code>
- </operation>
- <!--${QS::QS-tx::enum_dict_pre_}-->
- <operation name="enum_dict_pre_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output predefined enum-dictionary record
- * @static @private @memberof QS_tx
- *
- * @note This function is only to be used through macro QS_ENUM_DICTIONARY()
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::enum_dict_pre_::value}-->
- <parameter name="value" type="enum_t const"/>
- <!--${QS::QS-tx::enum_dict_pre_::group}-->
- <parameter name="group" type="uint8_t const"/>
- <!--${QS::QS-tx::enum_dict_pre_::name}-->
- <parameter name="name" type="char const * const"/>
- <code>QS_CRIT_STAT_
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_ENUM_DICT);
- QS_2U8_PRE_((uint8_t)value, group);
- QS_str_raw_(name);
- QS_endRec_();
- QS_CRIT_X_();
- QS_onFlush();</code>
- </operation>
- <!--${QS::QS-tx::ASSERTION}-->
- <operation name="ASSERTION" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output the predefined assertion failure trace record
- * @static @public @memberof QS_tx
- *
- * @details
- * This trace record is intended to use from the Q_onAssert() callback.
- */
- /*! @static @public @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::ASSERTION::module}-->
- <parameter name="module" type="char const * const"/>
- <!--${QS::QS-tx::ASSERTION::loc}-->
- <parameter name="loc" type="int_t const"/>
- <!--${QS::QS-tx::ASSERTION::delay}-->
- <parameter name="delay" type="uint32_t const"/>
- <code>QS_BEGIN_NOCRIT_PRE_(QS_ASSERT_FAIL, 0U)
- QS_TIME_PRE_();
- QS_U16_PRE_(loc);
- QS_STR_PRE_((module != (char *)0) ? module : "?");
- QS_END_NOCRIT_PRE_()
- QS_onFlush();
- for (uint32_t volatile delay_ctr = delay; delay_ctr > 0U; --delay_ctr) {
- }
- QS_onCleanup();</code>
- </operation>
- <!--${QS::QS-tx::target_info_pre_}-->
- <operation name="target_info_pre_" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Helper function to output the predefined Target-info trace record
- * @static @private @memberof QS_tx
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::target_info_pre_::isReset}-->
- <parameter name="isReset" type="uint8_t const"/>
- <code>static uint8_t const ZERO = (uint8_t)'0';
- static uint8_t const * const TIME = (uint8_t const *)&Q_BUILD_TIME[0];
- static uint8_t const * const DATE = (uint8_t const *)&Q_BUILD_DATE[0];
- static union {
- uint16_t u16;
- uint8_t u8[2];
- } endian_test;
- endian_test.u16 = 0x0102U;
- QS_beginRec_((uint_fast8_t)QS_TARGET_INFO);
- QS_U8_PRE_(isReset);
- QS_U16_PRE_(((endian_test.u8[0] == 0x01U) /* big endian? */
- ? (0x8000U | QP_VERSION)
- : QP_VERSION)); /* target endianness + version number */
- /* send the object sizes... */
- QS_U8_PRE_(Q_SIGNAL_SIZE | (QF_EVENT_SIZ_SIZE << 4U));
- #ifdef QF_EQUEUE_CTR_SIZE
- QS_U8_PRE_(QF_EQUEUE_CTR_SIZE | (QF_TIMEEVT_CTR_SIZE << 4U));
- #else
- QS_U8_PRE_(QF_TIMEEVT_CTR_SIZE << 4U);
- #endif /* QF_EQUEUE_CTR_SIZE */
- #ifdef QF_MPOOL_CTR_SIZE
- QS_U8_PRE_(QF_MPOOL_SIZ_SIZE | (QF_MPOOL_CTR_SIZE << 4U));
- #else
- QS_U8_PRE_(0U);
- #endif /* QF_MPOOL_CTR_SIZE */
- QS_U8_PRE_(QS_OBJ_PTR_SIZE | (QS_FUN_PTR_SIZE << 4U));
- QS_U8_PRE_(QS_TIME_SIZE);
- /* send the limits... */
- QS_U8_PRE_(QF_MAX_ACTIVE);
- QS_U8_PRE_(QF_MAX_EPOOL | (QF_MAX_TICK_RATE << 4U));
- /* send the build time in three bytes (sec, min, hour)... */
- QS_U8_PRE_((10U * (uint8_t)(TIME[6] - ZERO))
- + (uint8_t)(TIME[7] - ZERO));
- QS_U8_PRE_((10U * (uint8_t)(TIME[3] - ZERO))
- + (uint8_t)(TIME[4] - ZERO));
- if (Q_BUILD_TIME[0] == ' ') {
- QS_U8_PRE_(TIME[1] - ZERO);
- }
- else {
- QS_U8_PRE_((10U * (uint8_t)(TIME[0] - ZERO))
- + (uint8_t)(TIME[1] - ZERO));
- }
- /* send the build date in three bytes (day, month, year) ... */
- if (Q_BUILD_DATE[4] == ' ') {
- QS_U8_PRE_(DATE[5] - ZERO);
- }
- else {
- QS_U8_PRE_((10U * (uint8_t)(DATE[4] - ZERO))
- + (uint8_t)(DATE[5] - ZERO));
- }
- /* convert the 3-letter month to a number 1-12 ... */
- uint8_t b;
- switch ((int_t)DATE[0] + (int_t)DATE[1] + (int_t)DATE[2]) {
- case (int_t)'J' + (int_t)'a' + (int_t)'n':
- b = 1U;
- break;
- case (int_t)'F' + (int_t)'e' + (int_t)'b':
- b = 2U;
- break;
- case (int_t)'M' + (int_t)'a' + (int_t)'r':
- b = 3U;
- break;
- case (int_t)'A' + (int_t)'p' + (int_t)'r':
- b = 4U;
- break;
- case (int_t)'M' + (int_t)'a' + (int_t)'y':
- b = 5U;
- break;
- case (int_t)'J' + (int_t)'u' + (int_t)'n':
- b = 6U;
- break;
- case (int_t)'J' + (int_t)'u' + (int_t)'l':
- b = 7U;
- break;
- case (int_t)'A' + (int_t)'u' + (int_t)'g':
- b = 8U;
- break;
- case (int_t)'S' + (int_t)'e' + (int_t)'p':
- b = 9U;
- break;
- case (int_t)'O' + (int_t)'c' + (int_t)'t':
- b = 10U;
- break;
- case (int_t)'N' + (int_t)'o' + (int_t)'v':
- b = 11U;
- break;
- case (int_t)'D' + (int_t)'e' + (int_t)'c':
- b = 12U;
- break;
- default:
- b = 0U;
- break;
- }
- QS_U8_PRE_(b); /* store the month */
- QS_U8_PRE_((10U * (uint8_t)(DATE[9] - ZERO))
- + (uint8_t)(DATE[10] - ZERO));
- QS_endRec_();</code>
- </operation>
- <!--${QS::QS-tx::onStartup}-->
- <operation name="onStartup" type="uint8_t" visibility="0x00" properties="0x00">
- <documentation>/*! Callback to startup the QS facility
- * @static @public @memberof QS_tx
- */
- /*! @static @public @memberof QS_tx */</documentation>
- <!--${QS::QS-tx::onStartup::arg}-->
- <parameter name="arg" type="void const *"/>
- </operation>
- <!--${QS::QS-tx::onCleanup}-->
- <operation name="onCleanup" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Callback to cleanup the QS facility
- * @static @public @memberof QS_tx
- */
- /*! @static @public @memberof QS_tx */</documentation>
- </operation>
- <!--${QS::QS-tx::onFlush}-->
- <operation name="onFlush" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Callback to flush the QS trace data to the host
- * @static @public @memberof QS_tx
- */
- /*! @static @public @memberof QS_tx */</documentation>
- </operation>
- <!--${QS::QS-tx::onGetTime}-->
- <operation name="onGetTime" type="QSTimeCtr" visibility="0x00" properties="0x00">
- <documentation>/*! Callback to obtain a timestamp for a QS record
- * @static @public @memberof QS_tx
- */
- /*! @static @public @memberof QS_tx */</documentation>
- </operation>
- </package>
- <!--${QS::QS-tx-64bit}-->
- <package name="QS-tx-64bit" stereotype="0x02" namespace="QS_">
- <!--${QS::QS-tx-64bit::u64_raw_}-->
- <operation name="u64_raw_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output uint64_t data element without format information
- * @static @private @memberof QS_tx
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx-64bit::u64_raw_::d}-->
- <parameter name="d" type="uint64_t"/>
- <code>uint8_t chksum = QS_priv_.chksum;
- uint8_t * const buf = QS_priv_.buf;
- QSCtr head = QS_priv_.head;
- QSCtr const end = QS_priv_.end;
- QS_priv_.used += 8U; /* 8 bytes are about to be added */
- uint_fast8_t i;
- for (i = 8U; i != 0U; --i) {
- uint8_t const b = (uint8_t)d;
- QS_INSERT_ESC_BYTE_(b)
- d >>= 8U;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx-64bit::u64_fmt_}-->
- <operation name="u64_fmt_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output uint64_t data element with format information
- * @static @private @memberof QS_tx
- *
- * @sa QS_U64(), QS_I64()
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx-64bit::u64_fmt_::format}-->
- <parameter name="format" type="uint8_t"/>
- <!--${QS::QS-tx-64bit::u64_fmt_::d}-->
- <parameter name="d" type="uint64_t"/>
- <code>uint8_t chksum = QS_priv_.chksum;
- uint8_t * const buf = QS_priv_.buf;
- QSCtr head = QS_priv_.head;
- QSCtr const end = QS_priv_.end;
- QS_priv_.used += 9U; /* 9 bytes are about to be added */
- QS_INSERT_ESC_BYTE_(format) /* insert the format byte */
- /* output 8 bytes of data... */
- uint_fast8_t i;
- for (i = 8U; i != 0U; --i) {
- format = (uint8_t)d;
- QS_INSERT_ESC_BYTE_(format)
- d >>= 8U;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- </package>
- <!--${QS::QS-tx-fp}-->
- <package name="QS-tx-fp" stereotype="0x02" namespace="QS_">
- <!--${QS::QS-tx-fp::f32_fmt_}-->
- <operation name="f32_fmt_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output 32-bit floating point data element with format information
- * @static @private @memberof QS_tx
- *
- * @sa QS_F32()
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx-fp::f32_fmt_::format}-->
- <parameter name="format" type="uint8_t const"/>
- <!--${QS::QS-tx-fp::f32_fmt_::d}-->
- <parameter name="d" type="float32_t const"/>
- <code>union F32Rep {
- float32_t f;
- uint32_t u;
- } fu32; /* the internal binary representation */
- uint8_t chksum = QS_priv_.chksum; /* put in a temporary (register) */
- uint8_t * const buf = QS_priv_.buf;
- QSCtr head = QS_priv_.head;
- QSCtr const end = QS_priv_.end;
- uint_fast8_t i;
- fu32.f = d; /* assign the binary representation */
- QS_priv_.used += 5U; /* 5 bytes about to be added */
- QS_INSERT_ESC_BYTE_(format) /* insert the format byte */
- /* insert 4 bytes... */
- for (i = 4U; i != 0U; --i) {
- QS_INSERT_ESC_BYTE_((uint8_t)fu32.u)
- fu32.u >>= 8U;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- <!--${QS::QS-tx-fp::f64_fmt_}-->
- <operation name="f64_fmt_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Output 64-bit floating point data element with format information
- * @static @private @memberof QS_tx
- *
- * @sa QS_F64()
- */
- /*! @static @private @memberof QS_tx */</documentation>
- <!--${QS::QS-tx-fp::f64_fmt_::format}-->
- <parameter name="format" type="uint8_t const"/>
- <!--${QS::QS-tx-fp::f64_fmt_::d}-->
- <parameter name="d" type="float64_t const"/>
- <code>union F64Rep {
- float64_t d;
- uint32_t u[2];
- } fu64; /* the internal binary representation */
- uint8_t chksum = QS_priv_.chksum;
- uint8_t * const buf = QS_priv_.buf;
- QSCtr head = QS_priv_.head;
- QSCtr const end = QS_priv_.end;
- uint32_t i;
- /* static constant untion to detect endianness of the machine */
- static union U32Rep {
- uint32_t u32;
- uint8_t u8;
- } const endian = { 1U };
- fu64.d = d; /* assign the binary representation */
- /* is this a big-endian machine? */
- if (endian.u8 == 0U) {
- /* swap fu64.u[0] <-> fu64.u[1]... */
- i = fu64.u[0];
- fu64.u[0] = fu64.u[1];
- fu64.u[1] = i;
- }
- QS_priv_.used += 9U; /* 9 bytes about to be added */
- QS_INSERT_ESC_BYTE_(format) /* insert the format byte */
- /* output 4 bytes from fu64.u[0]... */
- for (i = 4U; i != 0U; --i) {
- QS_INSERT_ESC_BYTE_((uint8_t)fu64.u[0])
- fu64.u[0] >>= 8U;
- }
- /* output 4 bytes from fu64.u[1]... */
- for (i = 4U; i != 0U; --i) {
- QS_INSERT_ESC_BYTE_((uint8_t)fu64.u[1])
- fu64.u[1] >>= 8U;
- }
- QS_priv_.head = head; /* save the head */
- QS_priv_.chksum = chksum; /* save the checksum */</code>
- </operation>
- </package>
- <!--${QS::QS-rx}-->
- <package name="QS-rx" stereotype="0x02" namespace="QS_">
- <!--${QS::QS-rx::rx}-->
- <class name="rx">
- <documentation>/*! @brief QS software tracing parameters for QS input (QS-RX)
- * @class QS_rx
- */</documentation>
- <!--${QS::QS-rx::rx::currObj[8]}-->
- <attribute name="currObj[8]" type="void *" visibility="0x00" properties="0x00">
- <documentation>* current objects</documentation>
- </attribute>
- <!--${QS::QS-rx::rx::buf}-->
- <attribute name="buf" type="uint8_t *" visibility="0x00" properties="0x00">
- <documentation>* pointer to the start of the ring buffer</documentation>
- </attribute>
- <!--${QS::QS-rx::rx:: end}-->
- <attribute name=" end" type="QSCtr" visibility="0x00" properties="0x00">
- <documentation>* offset of the end of the ring buffer</documentation>
- </attribute>
- <!--${QS::QS-rx::rx::head}-->
- <attribute name="head" type="QSCtr volatile" visibility="0x00" properties="0x00">
- <documentation>* offset to where next byte will be inserted</documentation>
- </attribute>
- <!--${QS::QS-rx::rx::tail}-->
- <attribute name="tail" type="QSCtr volatile" visibility="0x00" properties="0x00">
- <documentation>* offset of where next byte will be extracted</documentation>
- </attribute>
- <!--${QS::QS-rx::rx::inTestLoop}-->
- <attribute name="inTestLoop?def Q_UTEST" type="bool" visibility="0x00" properties="0x00">
- <documentation>* QUTest event loop is running</documentation>
- </attribute>
- </class>
- <!--${QS::QS-rx::rxPriv_}-->
- <attribute name="rxPriv_" type="QS_rx" visibility="0x00" properties="0x01">
- <documentation>/*! the only instance of the QS-RX object (Singleton)
- * @static @private @memberof QS_rx
- */</documentation>
- </attribute>
- <!--${QS::QS-rx::QSpyObjKind}-->
- <attribute name="QSpyObjKind" type="enum" visibility="0x04" properties="0x01">
- <documentation>/*! Kinds of objects used in QS_setCurrObj() and QS_queryCurrObj()
- * @static @public @memberof QS_rx
- */</documentation>
- <code>{
- SM_OBJ, /*!< state machine object */
- AO_OBJ, /*!< active object */
- MP_OBJ, /*!< event pool object */
- EQ_OBJ, /*!< raw queue object */
- TE_OBJ, /*!< time event object */
- AP_OBJ, /*!< generic Application-specific object */
- MAX_OBJ
- };</code>
- </attribute>
- <!--${QS::QS-rx::OSpyObjCombnation}-->
- <attribute name="OSpyObjCombnation" type="enum" visibility="0x04" properties="0x01">
- <documentation>/*! Object combinations for QS_setCurrObj() and QS_queryCurrObj()
- * @static @public @memberof QS_rx
- */</documentation>
- <code>{
- SM_AO_OBJ = (enum_t)MAX_OBJ /*!< combination of SM and AO */
- };</code>
- </attribute>
- <!--${QS::QS-rx::rxInitBuf}-->
- <operation name="rxInitBuf" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Initialize the QS-RX data buffer
- * @static @public @memberof QS_rx
- *
- * @details
- * This function should be called from QS::onStartup() to provide QS-RX
- * with the receive data buffer.
- *
- * @param[in] sto pointer to the memory block for input buffer
- * @param[in] stoSize the size of this block [bytes]. The size of the
- * QS-RX buffer cannot exceed 64KB.
- *
- * @note
- * QS-RX can work with quite small data buffers, but you will start
- * losing data if the buffer is not drained fast enough (e.g., in the
- * idle task).
- *
- * @note
- * If the data input rate exceeds the QS-RX processing rate, the data
- * will be lost, but the QS protocol will notice that:
- * (1) that the checksum in the incomplete QS records will fail; and
- * (2) the sequence counter in QS records will show discontinuities.
- *
- * The QS-RX channel will report any data errors by sending the
- * QS_RX_DATA_ERROR trace record.
- */
- /*! @static @public @memberof QS_rx */</documentation>
- <!--${QS::QS-rx::rxInitBuf::sto}-->
- <parameter name="sto" type="uint8_t * const"/>
- <!--${QS::QS-rx::rxInitBuf::stoSize}-->
- <parameter name="stoSize" type="uint16_t const"/>
- <code>QS_rxPriv_.buf = &sto[0];
- QS_rxPriv_.end = (QSCtr)stoSize;
- QS_rxPriv_.head = 0U;
- QS_rxPriv_.tail = 0U;
- QS_rxPriv_.currObj[SM_OBJ] = (void *)0;
- QS_rxPriv_.currObj[AO_OBJ] = (void *)0;
- QS_rxPriv_.currObj[MP_OBJ] = (void *)0;
- QS_rxPriv_.currObj[EQ_OBJ] = (void *)0;
- QS_rxPriv_.currObj[TE_OBJ] = (void *)0;
- QS_rxPriv_.currObj[AP_OBJ] = (void *)0;
- QS_RX_TRAN_(WAIT4_SEQ);
- l_rx.esc = 0U;
- l_rx.seq = 0U;
- l_rx.chksum = 0U;
- QS_beginRec_((uint_fast8_t)QS_OBJ_DICT);
- QS_OBJ_PRE_(&QS_rxPriv_);
- QS_STR_PRE_("QS_RX");
- QS_endRec_();
- /* no QS_REC_DONE(), because QS is not running yet */
- #ifdef Q_UTEST
- QS_testData.tpNum = 0U;
- QS_testData.testTime = 0U;
- #endif /* Q_UTEST */</code>
- </operation>
- <!--${QS::QS-rx::rxPut}-->
- <operation name="rxPut" type="bool" visibility="0x00" properties="0x02">
- <documentation>/*! Put one byte into the QS-RX lock-free buffer
- * @static @public @memberof QS_rx
- */
- /*! @static @public @memberof QS_rx */</documentation>
- <!--${QS::QS-rx::rxPut::b}-->
- <parameter name="b" type="uint8_t const"/>
- <code>QSCtr head = QS_rxPriv_.head + 1U;
- if (head == QS_rxPriv_.end) {
- head = 0U;
- }
- if (head != QS_rxPriv_.tail) { /* buffer NOT full? */
- QS_rxPriv_.buf[QS_rxPriv_.head] = b;
- QS_rxPriv_.head = head; /* update the head to a *valid* index */
- return true; /* byte placed in the buffer */
- }
- else {
- return false; /* byte NOT placed in the buffer */
- }</code>
- </operation>
- <!--${QS::QS-rx::rxGetNfree}-->
- <operation name="rxGetNfree" type="uint16_t" visibility="0x00" properties="0x00">
- <documentation>/*! Obtain the number of free bytes in the QS-RX data buffer
- * @static @public @memberof QS_rx
- *
- * @details
- * This function is intended to be called from the ISR that reads the
- * QS-RX bytes from the QSPY application. The function returns the
- * conservative number of free bytes currently available in the buffer,
- * assuming that the head pointer is not being moved concurrently.
- * The tail pointer might be moving, meaning that bytes can be
- * concurrently removed from the buffer.
- */
- /*! @static @public @memberof QS_rx */</documentation>
- <code>QSCtr const head = QS_rxPriv_.head;
- if (head == QS_rxPriv_.tail) { /* buffer empty? */
- return (uint16_t)(QS_rxPriv_.end - 1U);
- }
- else if (head < QS_rxPriv_.tail) {
- return (uint16_t)(QS_rxPriv_.tail - (head + 1U));
- }
- else {
- return (uint16_t)(QS_rxPriv_.end + QS_rxPriv_.tail - (head + 1U));
- }</code>
- </operation>
- <!--${QS::QS-rx::doInput}-->
- <operation name="doInput" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Perform the QS-RX input (implemented in some QS ports)
- * @static @public @memberof QS_rx
- */
- /*! @static @public @memberof QS_rx */</documentation>
- </operation>
- <!--${QS::QS-rx::setCurrObj}-->
- <operation name="setCurrObj" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Set the "current object" in the Target
- * @static @public @memberof QS_rx
- *
- * @details
- * This function sets the "current object" in the Target.
- */
- /*! @static @public @memberof QS_rx */</documentation>
- <!--${QS::QS-rx::setCurrObj::obj_kind}-->
- <parameter name="obj_kind" type="uint8_t const"/>
- <!--${QS::QS-rx::setCurrObj::obj_ptr}-->
- <parameter name="obj_ptr" type="void * const"/>
- <code>Q_REQUIRE_ID(100, obj_kind < Q_DIM(QS_rxPriv_.currObj));
- QS_rxPriv_.currObj[obj_kind] = obj_ptr;</code>
- </operation>
- <!--${QS::QS-rx::queryCurrObj}-->
- <operation name="queryCurrObj" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Query the "current object" in the Target
- * @static @public @memberof QS_rx
- *
- * @details
- * This function programmatically generates the response to the query for
- * a "current object".
- */
- /*! @static @public @memberof QS_rx */</documentation>
- <!--${QS::QS-rx::queryCurrObj::obj_kind}-->
- <parameter name="obj_kind" type="uint8_t const"/>
- <code>if (QS_rxPriv_.currObj[obj_kind] != (void *)0) {
- QS_CRIT_STAT_
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_QUERY_DATA);
- QS_TIME_PRE_(); /* timestamp */
- QS_U8_PRE_(obj_kind); /* object kind */
- QS_OBJ_PRE_(QS_rxPriv_.currObj[obj_kind]);
- switch (obj_kind) {
- case (uint8_t)SM_OBJ: /* intentionally fall through */
- case (uint8_t)AO_OBJ:
- QS_FUN_PRE_((*((QHsm *)QS_rxPriv_.currObj[obj_kind])->vptr
- ->getStateHandler)(
- ((QHsm *)QS_rxPriv_.currObj[obj_kind])));
- break;
- case (uint8_t)MP_OBJ:
- QS_MPC_PRE_(((QMPool *)QS_rxPriv_.currObj[obj_kind])
- ->nFree);
- QS_MPC_PRE_(((QMPool *)QS_rxPriv_.currObj[obj_kind])
- ->nMin);
- break;
- case (uint8_t)EQ_OBJ:
- QS_EQC_PRE_(((QEQueue *)QS_rxPriv_.currObj[obj_kind])
- ->nFree);
- QS_EQC_PRE_(((QEQueue *)QS_rxPriv_.currObj[obj_kind])
- ->nMin);
- break;
- case (uint8_t)TE_OBJ:
- QS_OBJ_PRE_(((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
- ->act);
- QS_TEC_PRE_(((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
- ->ctr);
- QS_TEC_PRE_(((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
- ->interval);
- QS_SIG_PRE_(((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
- ->super.sig);
- QS_U8_PRE_ (((QTimeEvt *)QS_rxPriv_.currObj[obj_kind])
- ->super.refCtr_);
- break;
- default:
- /* intentionally empty */
- break;
- }
- QS_endRec_();
- QS_CRIT_X_();
- QS_REC_DONE(); /* user callback (if defined) */
- }
- else {
- QS_rxReportError_((int8_t)QS_RX_QUERY_CURR);
- }</code>
- </operation>
- <!--${QS::QS-rx::rxParse}-->
- <operation name="rxParse" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Parse all bytes present in the QS-RX data buffer
- * @static @public @memberof QS_rx
- */
- /*! @static @public @memberof QS_rx */</documentation>
- <code>QSCtr tail = QS_rxPriv_.tail;
- while (QS_rxPriv_.head != tail) { /* QS-RX buffer NOT empty? */
- uint8_t b = QS_rxPriv_.buf[tail];
- ++tail;
- if (tail == QS_rxPriv_.end) {
- tail = 0U;
- }
- QS_rxPriv_.tail = tail; /* update the tail to a *valid* index */
- if (l_rx.esc != 0U) { /* escaped byte arrived? */
- l_rx.esc = 0U;
- b ^= QS_ESC_XOR;
- l_rx.chksum += b;
- QS_rxParseData_(b);
- }
- else if (b == QS_ESC) {
- l_rx.esc = 1U;
- }
- else if (b == QS_FRAME) {
- /* get ready for the next frame */
- b = l_rx.state; /* save the current state in b */
- l_rx.esc = 0U;
- QS_RX_TRAN_(WAIT4_SEQ);
- if (l_rx.chksum == QS_GOOD_CHKSUM) {
- l_rx.chksum = 0U;
- QS_rxHandleGoodFrame_(b);
- }
- else { /* bad checksum */
- l_rx.chksum = 0U;
- QS_rxReportError_(0x41);
- QS_rxHandleBadFrame_(b);
- }
- }
- else {
- l_rx.chksum += b;
- QS_rxParseData_(b);
- }
- }</code>
- </operation>
- <!--${QS::QS-rx::rxHandleGoodFrame_}-->
- <operation name="rxHandleGoodFrame_" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! internal function to handle incoming (QS-RX) packet
- * @static @private @memberof QS_rx
- */
- /*! @static @private @memberof QS_rx */</documentation>
- <!--${QS::QS-rx::rxHandleGoodFram~::state}-->
- <parameter name="state" type="uint8_t const"/>
- <code>uint8_t i;
- uint8_t *ptr;
- QS_CRIT_STAT_
- switch (state) {
- case WAIT4_INFO_FRAME: {
- /* no need to report Ack or Done */
- QS_CRIT_E_();
- QS_target_info_pre_(0U); /* send only Target info */
- QS_CRIT_X_();
- break;
- }
- case WAIT4_RESET_FRAME: {
- /* no need to report Ack or Done, because Target resets */
- QS_onReset(); /* reset the Target */
- break;
- }
- case WAIT4_CMD_PARAM1: /* intentionally fall-through */
- case WAIT4_CMD_PARAM2: /* intentionally fall-through */
- case WAIT4_CMD_PARAM3: /* intentionally fall-through */
- case WAIT4_CMD_FRAME: {
- QS_rxReportAck_((int8_t)QS_RX_COMMAND);
- QS_onCommand(l_rx.var.cmd.cmdId, l_rx.var.cmd.param1,
- l_rx.var.cmd.param2, l_rx.var.cmd.param3);
- #ifdef Q_UTEST
- #if Q_UTEST != 0
- QS_processTestEvts_(); /* process all events produced */
- #endif /* Q_UTEST != 0 */
- #endif /* Q_UTEST */
- QS_rxReportDone_((int8_t)QS_RX_COMMAND);
- break;
- }
- case WAIT4_TICK_FRAME: {
- QS_rxReportAck_((int8_t)QS_RX_TICK);
- #ifdef Q_UTEST
- QTimeEvt_tick1_((uint_fast8_t)l_rx.var.tick.rate, &QS_rxPriv_);
- #if Q_UTEST != 0
- QS_processTestEvts_(); /* process all events produced */
- #endif /* Q_UTEST != 0 */
- #else
- QTimeEvt_tick_((uint_fast8_t)l_rx.var.tick.rate, &QS_rxPriv_);
- #endif /* Q_UTEST */
- QS_rxReportDone_((int8_t)QS_RX_TICK);
- break;
- }
- case WAIT4_PEEK_FRAME: {
- /* no need to report Ack or Done */
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_PEEK_DATA);
- ptr = (uint8_t *)QS_rxPriv_.currObj[AP_OBJ];
- ptr = &ptr[l_rx.var.peek.offs];
- QS_TIME_PRE_(); /* timestamp */
- QS_U16_PRE_(l_rx.var.peek.offs); /* data offset */
- QS_U8_PRE_(l_rx.var.peek.size); /* data size */
- QS_U8_PRE_(l_rx.var.peek.num); /* number of data items */
- for (i = 0U; i < l_rx.var.peek.num; ++i) {
- switch (l_rx.var.peek.size) {
- case 1:
- QS_U8_PRE_(ptr[i]);
- break;
- case 2:
- QS_U16_PRE_(((uint16_t *)ptr)[i]);
- break;
- case 4:
- QS_U32_PRE_(((uint32_t *)ptr)[i]);
- break;
- default:
- /* intentionally empty */
- break;
- }
- }
- QS_endRec_();
- QS_CRIT_X_();
- QS_REC_DONE(); /* user callback (if defined) */
- break;
- }
- case WAIT4_POKE_DATA: {
- /* received less than expected poke data items */
- QS_rxReportError_((int8_t)QS_RX_POKE);
- break;
- }
- case WAIT4_POKE_FRAME: {
- QS_rxReportAck_((int8_t)QS_RX_POKE);
- /* no need to report done */
- break;
- }
- case WAIT4_FILL_FRAME: {
- QS_rxReportAck_((int8_t)QS_RX_FILL);
- ptr = (uint8_t *)QS_rxPriv_.currObj[AP_OBJ];
- ptr = &ptr[l_rx.var.poke.offs];
- for (i = 0U; i < l_rx.var.poke.num; ++i) {
- switch (l_rx.var.poke.size) {
- case 1:
- ptr[i] = (uint8_t)l_rx.var.poke.data;
- break;
- case 2:
- ((uint16_t *)ptr)[i]
- = (uint16_t)l_rx.var.poke.data;
- break;
- case 4:
- ((uint32_t *)ptr)[i] = l_rx.var.poke.data;
- break;
- default:
- /* intentionally empty */
- break;
- }
- }
- break;
- }
- case WAIT4_FILTER_FRAME: {
- QS_rxReportAck_(l_rx.var.flt.recId);
- /* apply the received filters */
- if (l_rx.var.flt.recId == (int8_t)QS_RX_GLB_FILTER) {
- for (i = 0U; i < Q_DIM(QS_priv_.glbFilter); ++i) {
- QS_priv_.glbFilter[i] = l_rx.var.flt.data[i];
- }
- /* leave the "not maskable" filters enabled,
- * see qs.h, Miscellaneous QS records (not maskable)
- */
- QS_priv_.glbFilter[0] |= 0x01U;
- QS_priv_.glbFilter[7] |= 0xFCU;
- QS_priv_.glbFilter[8] |= 0x7FU;
- /* never enable the last 3 records (0x7D, 0x7E, 0x7F) */
- QS_priv_.glbFilter[15] &= 0x1FU;
- }
- else if (l_rx.var.flt.recId == (int8_t)QS_RX_LOC_FILTER) {
- for (i = 0U; i < Q_DIM(QS_priv_.locFilter); ++i) {
- QS_priv_.locFilter[i] = l_rx.var.flt.data[i];
- }
- /* leave QS_ID == 0 always on */
- QS_priv_.locFilter[0] |= 0x01U;
- }
- else {
- QS_rxReportError_(l_rx.var.flt.recId);
- }
- /* no need to report Done */
- break;
- }
- case WAIT4_OBJ_FRAME: {
- i = l_rx.var.obj.kind;
- if (i < (uint8_t)MAX_OBJ) {
- if (l_rx.var.obj.recId == (int8_t)QS_RX_CURR_OBJ) {
- QS_rxPriv_.currObj[i] = (void *)l_rx.var.obj.addr;
- QS_rxReportAck_((int8_t)QS_RX_CURR_OBJ);
- }
- else if (l_rx.var.obj.recId == (int8_t)QS_RX_AO_FILTER) {
- if (l_rx.var.obj.addr != 0U) {
- int_fast16_t const filter =
- (int_fast16_t)((QActive *)l_rx.var.obj.addr)->prio;
- QS_locFilter_((i == 0U)
- ? filter
- :-filter);
- QS_rxReportAck_((int8_t)QS_RX_AO_FILTER);
- }
- else {
- QS_rxReportError_((int8_t)QS_RX_AO_FILTER);
- }
- }
- else {
- QS_rxReportError_(l_rx.var.obj.recId);
- }
- }
- /* both SM and AO */
- else if (i == (uint8_t)SM_AO_OBJ) {
- if (l_rx.var.obj.recId == (int8_t)QS_RX_CURR_OBJ) {
- QS_rxPriv_.currObj[SM_OBJ] = (void *)l_rx.var.obj.addr;
- QS_rxPriv_.currObj[AO_OBJ] = (void *)l_rx.var.obj.addr;
- }
- QS_rxReportAck_(l_rx.var.obj.recId);
- }
- else {
- QS_rxReportError_(l_rx.var.obj.recId);
- }
- break;
- }
- case WAIT4_QUERY_FRAME: {
- QS_queryCurrObj(l_rx.var.obj.kind);
- break;
- }
- case WAIT4_EVT_FRAME: {
- /* NOTE: Ack was already reported in the WAIT4_EVT_LEN state */
- #ifdef Q_UTEST
- QS_onTestEvt(l_rx.var.evt.e); /* adjust the event, if needed */
- #endif /* Q_UTEST */
- i = 0U; /* use 'i' as status, 0 == success,no-recycle */
- if (l_rx.var.evt.prio == 0U) { /* publish */
- QActive_publish_(l_rx.var.evt.e, &QS_rxPriv_, 0U);
- }
- else if (l_rx.var.evt.prio < QF_MAX_ACTIVE) {
- if (!QACTIVE_POST_X(QActive_registry_[l_rx.var.evt.prio],
- l_rx.var.evt.e,
- 0U, /* margin */
- &QS_rxPriv_))
- {
- /* failed QACTIVE_POST() recycles the event */
- i = 0x80U; /* failure status, no recycle */
- }
- }
- else if (l_rx.var.evt.prio == 255U) { /* special prio */
- /* dispatch to the current SM object */
- if (QS_rxPriv_.currObj[SM_OBJ] != (void *)0) {
- /* increment the ref-ctr to simulate the situation
- * when the event is just retreived from a queue.
- * This is expected for the following QF_gc() call.
- */
- ++l_rx.var.evt.e->refCtr_;
- QHSM_DISPATCH((QHsm *)QS_rxPriv_.currObj[SM_OBJ],
- l_rx.var.evt.e, 0U);
- i = 0x01U; /* success status, recycle needed */
- }
- else {
- i = 0x81U; /* failure status, recycle needed */
- }
- }
- else if (l_rx.var.evt.prio == 254U) { /* special prio */
- /* init the current SM object" */
- if (QS_rxPriv_.currObj[SM_OBJ] != (void *)0) {
- /* increment the ref-ctr to simulate the situation
- * when the event is just retreived from a queue.
- * This is expected for the following QF_gc() call.
- */
- ++l_rx.var.evt.e->refCtr_;
- QHSM_INIT((QHsm *)QS_rxPriv_.currObj[SM_OBJ],
- l_rx.var.evt.e, 0U);
- i = 0x01U; /* success status, recycle needed */
- }
- else {
- i = 0x81U; /* failure status, recycle needed */
- }
- }
- else if (l_rx.var.evt.prio == 253U) { /* special prio */
- /* post to the current AO */
- if (QS_rxPriv_.currObj[AO_OBJ] != (void *)0) {
- if (!QACTIVE_POST_X(
- (QActive *)QS_rxPriv_.currObj[AO_OBJ],
- l_rx.var.evt.e,
- 0U, /* margin */
- &QS_rxPriv_))
- {
- /* failed QACTIVE_POST() recycles the event */
- i = 0x80U; /* failure status, no recycle */
- }
- }
- else {
- i = 0x81U; /* failure status, recycle needed */
- }
- }
- else {
- i = 0x81U; /* failure status, recycle needed */
- }
- #if (QF_MAX_EPOOL > 0U)
- if ((i & 0x01U) != 0U) { /* recycle needed? */
- QF_gc(l_rx.var.evt.e);
- }
- #endif
- if ((i & 0x80U) != 0U) { /* failure? */
- QS_rxReportError_((int8_t)QS_RX_EVENT);
- }
- else {
- #ifdef Q_UTEST
- #if Q_UTEST != 0
- QS_processTestEvts_(); /* process all events produced */
- #endif /* Q_UTEST != 0 */
- #endif /* Q_UTEST */
- QS_rxReportDone_((int8_t)QS_RX_EVENT);
- }
- break;
- }
- #ifdef Q_UTEST
- case WAIT4_TEST_SETUP_FRAME: {
- QS_rxReportAck_((int8_t)QS_RX_TEST_SETUP);
- QS_testData.tpNum = 0U; /* clear the Test-Probes */
- QS_testData.testTime = 0U; /* clear the time tick */
- /* don't clear current objects */
- QS_onTestSetup(); /* application-specific test setup */
- /* no need to report Done */
- break;
- }
- case WAIT4_TEST_TEARDOWN_FRAME: {
- QS_rxReportAck_((int8_t)QS_RX_TEST_TEARDOWN);
- QS_onTestTeardown(); /* application-specific test teardown */
- /* no need to report Done */
- break;
- }
- case WAIT4_TEST_CONTINUE_FRAME: {
- QS_rxReportAck_((int8_t)QS_RX_TEST_CONTINUE);
- QS_rxPriv_.inTestLoop = false; /* exit the QUTest loop */
- /* no need to report Done */
- break;
- }
- case WAIT4_TEST_PROBE_FRAME: {
- QS_rxReportAck_((int8_t)QS_RX_TEST_PROBE);
- Q_ASSERT_ID(815, QS_testData.tpNum
- < (sizeof(QS_testData.tpBuf) / sizeof(QS_testData.tpBuf[0])));
- QS_testData.tpBuf[QS_testData.tpNum] = l_rx.var.tp;
- ++QS_testData.tpNum;
- /* no need to report Done */
- break;
- }
- #endif /* Q_UTEST */
- case ERROR_STATE: {
- /* keep ignoring all bytes until new frame */
- break;
- }
- default: {
- QS_rxReportError_(0x47);
- break;
- }
- }</code>
- </operation>
- <!--${QS::QS-rx::onReset}-->
- <operation name="onReset" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! callback function to reset the Target (to be implemented in the BSP)
- * @static @public @memberof QS_rx
- */
- /*! @static @public @memberof QS_rx */</documentation>
- </operation>
- <!--${QS::QS-rx::onCommand}-->
- <operation name="onCommand" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Callback function to execute user commands (to be implemented in BSP)
- * @static @public @memberof QS_rx
- */
- /*! @static @public @memberof QS_rx */</documentation>
- <!--${QS::QS-rx::onCommand::cmdId}-->
- <parameter name="cmdId" type="uint8_t"/>
- <!--${QS::QS-rx::onCommand::param1}-->
- <parameter name="param1" type="uint32_t"/>
- <!--${QS::QS-rx::onCommand::param2}-->
- <parameter name="param2" type="uint32_t"/>
- <!--${QS::QS-rx::onCommand::param3}-->
- <parameter name="param3" type="uint32_t"/>
- </operation>
- <!--${QS::QS-rx::RX_PUT}-->
- <operation name="RX_PUT" type="bool" visibility="0x00" properties="0x00">
- <documentation>/*! Put one byte into the QS RX lock-free buffer
- * @static @public @memberof QS_rx
- */
- /*! @static @public @memberof QS_rx */</documentation>
- <!--${QS::QS-rx::RX_PUT::b}-->
- <parameter name="b" type="uint8_t const"/>
- <code>QSCtr head = QS_rxPriv_.head + 1U;
- if (head == QS_rxPriv_.end) {
- head = 0U;
- }
- if (head != QS_rxPriv_.tail) { /* buffer NOT full? */
- QS_rxPriv_.buf[QS_rxPriv_.head] = b;
- QS_rxPriv_.head = head; /* update the head to a *valid* index */
- return true; /* byte placed in the buffer */
- }
- else {
- return false; /* byte NOT placed in the buffer */
- }</code>
- </operation>
- </package>
- </package>
- <!--${QUTest}-->
- <package name="QUTest" stereotype="0x05">
- <!--${QUTest::QS}-->
- <package name="QS" stereotype="0x02" namespace="QS_">
- <!--${QUTest::QS::TProbe}-->
- <attribute name="TProbe" type="struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief Test Probe attributes */</documentation>
- <code>{
- QSFun addr;
- uint32_t data;
- uint8_t idx;
- };</code>
- </attribute>
- <!--${QUTest::QS::TestData}-->
- <attribute name="TestData" type="struct" visibility="0x04" properties="0x00">
- <documentation>/*! @brief QUTest data */</documentation>
- <code>{
- struct QS_TProbe tpBuf[16]; /*!< buffer of Test-Probes received so far */
- uint8_t tpNum; /*!< current number of Test-Probes */
- QSTimeCtr testTime; /*!< test time (tick counter) */
- };</code>
- </attribute>
- <!--${QUTest::QS::testData}-->
- <attribute name="testData" type="struct QS_TestData" visibility="0x00" properties="0x00">
- <documentation>/*! QUTest data */</documentation>
- </attribute>
- <!--${QUTest::QS::test_pause_}-->
- <operation name="test_pause_" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! internal function to pause test and enter the test event loop */</documentation>
- <code>QS_beginRec_((uint_fast8_t)QS_TEST_PAUSED);
- QS_endRec_();
- QS_onTestLoop();</code>
- </operation>
- <!--${QUTest::QS::getTestProbe_}-->
- <operation name="getTestProbe_" type="uint32_t" visibility="0x00" properties="0x00">
- <documentation>/*! get the test probe data for the given API */</documentation>
- <!--${QUTest::QS::getTestProbe_::api}-->
- <parameter name="api" type="QSpyFunPtr const"/>
- <code>uint32_t data = 0U;
- uint_fast8_t i;
- for (i = 0U; i < QS_testData.tpNum; ++i) {
- uint_fast8_t j;
- if (QS_testData.tpBuf[i].addr == (QSFun)api) {
- QS_CRIT_STAT_
- data = QS_testData.tpBuf[i].data;
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_TEST_PROBE_GET);
- QS_TIME_PRE_(); /* timestamp */
- QS_FUN_PRE_(api); /* the calling API */
- QS_U32_PRE_(data); /* the Test-Probe data */
- QS_endRec_();
- QS_CRIT_X_();
- QS_REC_DONE(); /* user callback (if defined) */
- --QS_testData.tpNum; /* one less Test-Probe */
- /* move all remaining entries in the buffer up by one */
- for (j = i; j < QS_testData.tpNum; ++j) {
- QS_testData.tpBuf[j] = QS_testData.tpBuf[j + 1U];
- }
- break; /* we are done (Test-Probe retreived) */
- }
- }
- return data;</code>
- </operation>
- <!--${QUTest::QS::onTestSetup}-->
- <operation name="onTestSetup" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! callback to setup a unit test inside the Target */</documentation>
- </operation>
- <!--${QUTest::QS::onTestTeardown}-->
- <operation name="onTestTeardown" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! callback to teardown after a unit test inside the Target */</documentation>
- </operation>
- <!--${QUTest::QS::onTestEvt}-->
- <operation name="onTestEvt" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! callback to "massage" the test event before dispatching/posting it */</documentation>
- <!--${QUTest::QS::onTestEvt::e}-->
- <parameter name="e" type="QEvt *"/>
- </operation>
- <!--${QUTest::QS::onTestPost}-->
- <operation name="onTestPost" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! callback to examine an event that is about to be posted */</documentation>
- <!--${QUTest::QS::onTestPost::sender}-->
- <parameter name="sender" type="void const *"/>
- <!--${QUTest::QS::onTestPost::recipient}-->
- <parameter name="recipient" type="QActive *"/>
- <!--${QUTest::QS::onTestPost::e}-->
- <parameter name="e" type="QEvt const *"/>
- <!--${QUTest::QS::onTestPost::status}-->
- <parameter name="status" type="bool"/>
- </operation>
- <!--${QUTest::QS::onTestLoop}-->
- <operation name="onTestLoop" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! callback to run the test loop */</documentation>
- </operation>
- </package>
- <!--${QUTest::QUTEST_ON_POST}-->
- <attribute name="QUTEST_ON_POST" type="124" visibility="0x03" properties="0x00">
- <documentation>/*! record-ID for posting events */</documentation>
- <code>124</code>
- </attribute>
- </package>
- <!--${QUTest-stub}-->
- <package name="QUTest-stub" stereotype="0x05">
- <!--${QUTest-stub::QS}-->
- <package name="QS" stereotype="0x02" namespace="QS_">
- <!--${QUTest-stub::QS::processTestEvts_}-->
- <operation name="processTestEvts_" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! internal function to process posted events during test */</documentation>
- <code>QS_TEST_PROBE_DEF(&QS_processTestEvts_)
- /* return immediately (do nothing) for Test Probe != 0 */
- QS_TEST_PROBE(return;)
- while (QPSet_notEmpty(&QF_readySet_)) {
- uint_fast8_t const p = QPSet_findMax(&QF_readySet_);
- QActive * const a = QActive_registry_[p];
- /* perform the run-to-completion (RTC) step...
- * 1. retrieve the event from the AO's event queue, which by this
- * time must be non-empty and The "Vanialla" kernel asserts it.
- * 2. dispatch the event to the AO's state machine.
- * 3. determine if event is garbage and collect it if so
- */
- QEvt const * const e = QActive_get_(a);
- QHSM_DISPATCH(&a->super, e, a->prio);
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e);
- #endif
- if (a->eQueue.frontEvt == (QEvt *)0) { /* empty queue? */
- QPSet_remove(&QF_readySet_, p);
- }
- }</code>
- </operation>
- </package>
- <!--${QUTest-stub::QF}-->
- <package name="QF" stereotype="0x02" namespace="QF_">
- <!--${QUTest-stub::QF::init}-->
- <operation name="init" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! QF initialization for QUTest */</documentation>
- <code>/* Clear the internal QF variables, so that the framework can start
- * correctly even if the startup code fails to clear the uninitialized
- * data (as is required by the C Standard).
- */
- QF_maxPool_ = 0U;
- QF_intLock_ = 0U;
- QF_intNest_ = 0U;
- QF_bzero(&QActive_registry_[0], sizeof(QActive_registry_));
- QF_bzero(&QF_readySet_, sizeof(QF_readySet_));</code>
- </operation>
- <!--${QUTest-stub::QF::stop}-->
- <operation name="stop" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! stop the QF customization for QUTest */</documentation>
- <code>QS_onReset();</code>
- </operation>
- <!--${QUTest-stub::QF::run}-->
- <operation name="run" type="int_t" visibility="0x00" properties="0x01">
- <documentation>/*! QF_run() customization for QUTest */</documentation>
- <code>/* function dictionaries for the standard API */
- QS_FUN_DICTIONARY(&QActive_post_);
- QS_FUN_DICTIONARY(&QActive_postLIFO_);
- QS_FUN_DICTIONARY(&QS_processTestEvts_);
- /* produce the QS_QF_RUN trace record */
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QF_RUN, 0U)
- QS_END_PRE_()
- QS_processTestEvts_(); /* process all events posted so far */
- QS_onTestLoop(); /* run the test loop */
- QS_onCleanup(); /* application cleanup */
- return 0; /* return no error */</code>
- </operation>
- </package>
- <!--${QUTest-stub::QActive}-->
- <class name="QActive" superclass="QEP::QHsm">
- <documentation>/*! QActive active object class customization for QUTest */</documentation>
- <!--${QUTest-stub::QActive::start_}-->
- <operation name="start_" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! QActive_start_() customization for QUTest
- * @public @memberof QActive
- */</documentation>
- <!--${QUTest-stub::QActive::start_::prioSpec}-->
- <parameter name="prioSpec" type="QPrioSpec const"/>
- <!--${QUTest-stub::QActive::start_::qSto}-->
- <parameter name="qSto" type="QEvt const * * const"/>
- <!--${QUTest-stub::QActive::start_::qLen}-->
- <parameter name="qLen" type="uint_fast16_t const"/>
- <!--${QUTest-stub::QActive::start_::stkSto}-->
- <parameter name="stkSto" type="void * const"/>
- <!--${QUTest-stub::QActive::start_::stkSize}-->
- <parameter name="stkSize" type="uint_fast16_t const"/>
- <!--${QUTest-stub::QActive::start_::par}-->
- <parameter name="par" type="void const * const"/>
- <code>Q_UNUSED_PAR(stkSto);
- Q_UNUSED_PAR(stkSize);
- me->prio = (uint8_t)(prioSpec & 0xFFU); /* QF-priority of the AO */
- me->pthre = (uint8_t)(prioSpec >> 8U); /* preemption-threshold */
- QActive_register_(me); /* make QF aware of this active object */
- QEQueue_init(&me->eQueue, qSto, qLen); /* initialize the built-in queue */
- QHSM_INIT(&me->super, par, me->prio); /* the top-most initial tran. */</code>
- </operation>
- <!--${QUTest-stub::QActive::stop}-->
- <operation name="stop?def QF_ACTIVE_STOP" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Stops execution of an active object and unregisters the object
- * with the framework customized for QUTest
- * @public @memberof QActive
- */</documentation>
- <code>QActive_unsubscribeAll(me); /* unsubscribe from all events */
- QActive_unregister_(me); /* un-register this active object */</code>
- </operation>
- </class>
- <!--${QUTest-stub::QTimeEvt}-->
- <class name="QTimeEvt" superclass="QEP::QEvt">
- <documentation>/*! QTimeEvt class customization for QUTest */</documentation>
- <!--${QUTest-stub::QTimeEvt::tick1_}-->
- <operation name="tick1_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! Processes one clock tick for QUTest */</documentation>
- <!--${QUTest-stub::QTimeEvt::tick1_::tickRate}-->
- <parameter name="tickRate" type="uint_fast8_t const"/>
- <!--${QUTest-stub::QTimeEvt::tick1_::sender}-->
- <parameter name="sender" type="void const * const"/>
- <code>QF_CRIT_STAT_
- QF_CRIT_E_();
- QTimeEvt *prev = &QTimeEvt_timeEvtHead_[tickRate];
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TICK, 0U)
- ++prev->ctr;
- QS_TEC_PRE_(prev->ctr); /* tick ctr */
- QS_U8_PRE_(tickRate); /* tick rate */
- QS_END_NOCRIT_PRE_()
- /* is current Time Event object provided? */
- QTimeEvt *t = (QTimeEvt *)QS_rxPriv_.currObj[TE_OBJ];
- if (t != (QTimeEvt *)0) {
- /* the time event must be armed */
- Q_ASSERT_ID(810, t->ctr != 0U);
- QActive * const act = (QActive * const)(t->act);
- /* the recipient AO must be provided */
- Q_ASSERT_ID(820, act != (QActive *)0);
- /* periodic time evt? */
- if (t->interval != 0U) {
- t->ctr = t->interval; /* rearm the time event */
- }
- else { /* one-shot time event: automatically disarm */
- t->ctr = 0U; /* auto-disarm */
- /* mark time event 't' as NOT linked */
- t->super.refCtr_ &= (uint8_t)(~(uint8_t)QTE_IS_LINKED);
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_AUTO_DISARM, act->prio)
- QS_OBJ_PRE_(t); /* this time event object */
- QS_OBJ_PRE_(act); /* the target AO */
- QS_U8_PRE_(tickRate); /* tick rate */
- QS_END_NOCRIT_PRE_()
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_TIMEEVT_POST, act->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(t); /* the time event object */
- QS_SIG_PRE_(t->super.sig); /* signal of this time event */
- QS_OBJ_PRE_(act); /* the target AO */
- QS_U8_PRE_(tickRate); /* tick rate */
- QS_END_NOCRIT_PRE_()
- QF_CRIT_X_(); /* exit critical section before posting */
- QACTIVE_POST(act, &t->super, sender); /* asserts if queue overflows */
- QF_CRIT_E_();
- }
- /* update the linked list of time events */
- for (;;) {
- t = prev->next; /* advance down the time evt. list */
- /* end of the list? */
- if (t == (QTimeEvt *)0) {
- /* any new time events armed since the last QTimeEvt_tick_()? */
- if (QTimeEvt_timeEvtHead_[tickRate].act != (void *)0) {
- /* sanity check */
- Q_ASSERT_CRIT_(830, prev != (QTimeEvt *)0);
- prev->next = (QTimeEvt *)QTimeEvt_timeEvtHead_[tickRate].act;
- QTimeEvt_timeEvtHead_[tickRate].act = (void *)0;
- t = prev->next; /* switch to the new list */
- }
- else {
- break; /* all currently armed time evts. processed */
- }
- }
- /* time event scheduled for removal? */
- if (t->ctr == 0U) {
- prev->next = t->next;
- /* mark time event 't' as NOT linked */
- t->super.refCtr_ &= (uint8_t)(~(uint8_t)QTE_IS_LINKED);
- /* do NOT advance the prev pointer */
- QF_CRIT_X_(); /* exit crit. section to reduce latency */
- /* prevent merging critical sections, see NOTE1 below */
- QF_CRIT_EXIT_NOP();
- }
- else {
- prev = t; /* advance to this time event */
- QF_CRIT_X_(); /* exit crit. section to reduce latency */
- /* prevent merging critical sections, see NOTE1 below */
- QF_CRIT_EXIT_NOP();
- }
- QF_CRIT_E_(); /* re-enter crit. section to continue */
- }
- QF_CRIT_X_();
- </code>
- </operation>
- </class>
- <!--${QUTest-stub::QHsmDummy}-->
- <class name="QHsmDummy" superclass="QEP::QHsm">
- <documentation>/*! @brief QHsmDummy class
- * @class QHsmDummy
- * @extends QHsm
- *
- * @details
- * ::QHsmDummy is a test double for the role of "Orthogonal Components"
- * HSM objects in QUTest unit testing.
- */</documentation>
- <!--${QUTest-stub::QHsmDummy::ctor}-->
- <operation name="ctor" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Constructor of the QHsmDummy HSM class
- * @public @memberof QHsmDummy
- */</documentation>
- <code>static struct QHsmVtable const vtable = { /* QHsm virtual table */
- &QHsmDummy_init_,
- &QHsmDummy_dispatch_
- #ifdef Q_SPY
- ,&QHsm_getStateHandler_
- #endif
- };
- /* superclass' ctor */
- QHsm_ctor(&me->super, Q_STATE_CAST(0));
- me->super.vptr = &vtable; /* hook the vptr */</code>
- </operation>
- <!--${QUTest-stub::QHsmDummy::init_}-->
- <operation name="init_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! override for QHsm_init_()
- * @private @memberof QHsmDummy
- */</documentation>
- <!--${QUTest-stub::QHsmDummy::init_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QUTest-stub::QHsmDummy::init_::par}-->
- <parameter name="par" type="void const * const"/>
- <!--${QUTest-stub::QHsmDummy::init_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>Q_UNUSED_PAR(par);
- #ifdef Q_SPY
- if ((QS_priv_.flags & 0x01U) == 0U) {
- QS_priv_.flags |= 0x01U;
- QS_FUN_DICTIONARY(&QHsm_top);
- }
- #endif
- QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_STATE_INIT, qs_id)
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(me->state.fun); /* the source state */
- QS_FUN_PRE_(me->temp.fun); /* the target of the initial transition */
- QS_END_PRE_()</code>
- </operation>
- <!--${QUTest-stub::QHsmDummy::dispatch_}-->
- <operation name="dispatch_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! override for QHsm_dispatch_()
- * @private @memberof QHsmDummy
- */</documentation>
- <!--${QUTest-stub::QHsmDummy::dispatch_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QUTest-stub::QHsmDummy::dispatch_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QUTest-stub::QHsmDummy::dispatch_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>QS_CRIT_STAT_
- QS_BEGIN_PRE_(QS_QEP_DISPATCH, qs_id)
- QS_TIME_PRE_(); /* time stamp */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this state machine object */
- QS_FUN_PRE_(me->state.fun); /* the current state */
- QS_END_PRE_()</code>
- </operation>
- </class>
- <!--${QUTest-stub::QActiveDummy}-->
- <class name="QActiveDummy" superclass="QF::QActive">
- <documentation>/*! @brief QActiveDummy Object class
- * @class QActiveDummy
- * @extends QActive
- *
- * @details
- * QActiveDummy is a test double for the role of collaborating active
- * objects in QUTest unit testing.
- */</documentation>
- <!--${QUTest-stub::QActiveDummy::ctor}-->
- <operation name="ctor" type="void" visibility="0x00" properties="0x00">
- <documentation>/*! Constructor of the QActiveDummy Active Object class
- * @public @memberof QActiveDummy
- */</documentation>
- <code>static QActiveVtable const vtable = { /* QActive virtual table */
- { &QActiveDummy_init_,
- &QActiveDummy_dispatch_
- #ifdef Q_SPY
- ,&QHsm_getStateHandler_
- #endif
- },
- &QActiveDummy_start_,
- &QActiveDummy_post_,
- &QActiveDummy_postLIFO_
- };
- /* superclass' ctor */
- QActive_ctor(&me->super, Q_STATE_CAST(0));
- me->super.super.vptr = &vtable.super; /* hook the vptr */</code>
- </operation>
- <!--${QUTest-stub::QActiveDummy::init_}-->
- <operation name="init_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! override for QHsm_init_()
- * @private @memberof QActiveDummy
- */</documentation>
- <!--${QUTest-stub::QActiveDummy::init_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QUTest-stub::QActiveDummy::init_::par}-->
- <parameter name="par" type="void const * const"/>
- <!--${QUTest-stub::QActiveDummy::init_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>Q_UNUSED_PAR(qs_id);
- QHsmDummy_init_(me, par, ((QActive const *)me)->prio);</code>
- </operation>
- <!--${QUTest-stub::QActiveDummy::dispatch_}-->
- <operation name="dispatch_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! override for QHsm_dispatch_()
- * @private @memberof QActiveDummy
- */</documentation>
- <!--${QUTest-stub::QActiveDummy::dispatch_::me}-->
- <parameter name="me" type="QHsm * const"/>
- <!--${QUTest-stub::QActiveDummy::dispatch_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QUTest-stub::QActiveDummy::dispatch_::qs_id}-->
- <parameter name="qs_id" type="uint_fast8_t const"/>
- <code>Q_UNUSED_PAR(qs_id);
- QHsmDummy_dispatch_(me, e, ((QActive const *)me)->prio);</code>
- </operation>
- <!--${QUTest-stub::QActiveDummy::start_}-->
- <operation name="start_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! override for QActive_start_()
- * @private @memberof QActiveDummy
- */</documentation>
- <!--${QUTest-stub::QActiveDummy::start_::me}-->
- <parameter name="me" type="QActive * const"/>
- <!--${QUTest-stub::QActiveDummy::start_::prioSpec}-->
- <parameter name="prioSpec" type="QPrioSpec const"/>
- <!--${QUTest-stub::QActiveDummy::start_::qSto}-->
- <parameter name="qSto" type="QEvt const * * const"/>
- <!--${QUTest-stub::QActiveDummy::start_::qLen}-->
- <parameter name="qLen" type="uint_fast16_t const"/>
- <!--${QUTest-stub::QActiveDummy::start_::stkSto}-->
- <parameter name="stkSto" type="void * const"/>
- <!--${QUTest-stub::QActiveDummy::start_::stkSize}-->
- <parameter name="stkSize" type="uint_fast16_t const"/>
- <!--${QUTest-stub::QActiveDummy::start_::par}-->
- <parameter name="par" type="void const * const"/>
- <code>/* No special preconditions for checking parameters to allow starting
- * dummy AOs the exact same way as the real counterparts.
- */
- Q_UNUSED_PAR(qSto);
- Q_UNUSED_PAR(qLen);
- Q_UNUSED_PAR(stkSto);
- Q_UNUSED_PAR(stkSize);
- me->prio = (uint8_t)(prioSpec & 0xFFU); /* QF-priority of the AO */
- me->pthre = (uint8_t)(prioSpec >> 8U); /* preemption-threshold */
- QActive_register_(me); /* make QF aware of this active object */
- /* the top-most initial tran. (virtual) */
- QHSM_INIT(&me->super, par, me->prio);
- //QS_FLUSH();</code>
- </operation>
- <!--${QUTest-stub::QActiveDummy::post_}-->
- <operation name="post_" type="bool" visibility="0x00" properties="0x01">
- <documentation>/*! override for QActive_post_()
- * @private @memberof QActiveDummy
- */</documentation>
- <!--${QUTest-stub::QActiveDummy::post_::me}-->
- <parameter name="me" type="QActive * const"/>
- <!--${QUTest-stub::QActiveDummy::post_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <!--${QUTest-stub::QActiveDummy::post_::margin}-->
- <parameter name="margin" type="uint_fast16_t const"/>
- <!--${QUTest-stub::QActiveDummy::post_::sender}-->
- <parameter name="sender" type="void const * const"/>
- <code>QS_TEST_PROBE_DEF(&QActive_post_)
- /* test-probe#1 for faking queue overflow */
- bool status = true;
- QS_TEST_PROBE_ID(1,
- status = false;
- if (margin == QF_NO_MARGIN) {
- /* fake assertion Mod=qf_actq,Loc=110 */
- Q_onAssert("qf_actq", 110);
- }
- )
- QF_CRIT_STAT_
- QF_CRIT_E_();
- /* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- QEvt_refCtr_inc_(e); /* increment the reference counter */
- }
- uint_fast8_t const rec = (status ? (uint_fast8_t)QS_QF_ACTIVE_POST
- : (uint_fast8_t)QS_QF_ACTIVE_POST_ATTEMPT);
- QS_BEGIN_NOCRIT_PRE_(rec, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_OBJ_PRE_(sender); /* the sender object */
- QS_SIG_PRE_(e->sig); /* the signal of the event */
- QS_OBJ_PRE_(me); /* this active object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & refCtr of the evt */
- QS_EQC_PRE_(0U); /* number of free entries */
- QS_EQC_PRE_(margin); /* margin requested */
- QS_END_NOCRIT_PRE_()
- /* callback to examine the posted event under the same conditions
- * as producing the #QS_QF_ACTIVE_POST trace record, which are:
- * the local filter for this AO ('me->prio') is set
- */
- if ((QS_priv_.locFilter[me->prio >> 3U]
- & (1U << (me->prio & 7U))) != 0U)
- {
- QS_onTestPost(sender, me, e, status);
- }
- QF_CRIT_X_();
- /* recycle the event immediately, because it was not really posted */
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e);
- #endif
- return status; /* the event is "posted" correctly */</code>
- </operation>
- <!--${QUTest-stub::QActiveDummy::postLIFO_}-->
- <operation name="postLIFO_" type="void" visibility="0x00" properties="0x01">
- <documentation>/*! override for QActive_postLIFO_()
- * @private @memberof QActiveDummy
- */</documentation>
- <!--${QUTest-stub::QActiveDummy::postLIFO_::me}-->
- <parameter name="me" type="QActive * const"/>
- <!--${QUTest-stub::QActiveDummy::postLIFO_::e}-->
- <parameter name="e" type="QEvt const * const"/>
- <code>QS_TEST_PROBE_DEF(&QActive_postLIFO_)
- /* test-probe#1 for faking queue overflow */
- QS_TEST_PROBE_ID(1,
- /* fake assertion Mod=qf_actq,Loc=210 */
- Q_onAssert("qf_actq", 210);
- )
- QF_CRIT_STAT_
- QF_CRIT_E_();
- /* is it a dynamic event? */
- if (e->poolId_ != 0U) {
- QEvt_refCtr_inc_(e); /* increment the reference counter */
- }
- QS_BEGIN_NOCRIT_PRE_(QS_QF_ACTIVE_POST_LIFO, me->prio)
- QS_TIME_PRE_(); /* timestamp */
- QS_SIG_PRE_(e->sig); /* the signal of this event */
- QS_OBJ_PRE_(me); /* this active object */
- QS_2U8_PRE_(e->poolId_, e->refCtr_); /* pool Id & refCtr of the evt */
- QS_EQC_PRE_(0U); /* number of free entries */
- QS_EQC_PRE_(0U); /* min number of free entries */
- QS_END_NOCRIT_PRE_()
- /* callback to examine the posted event under the same conditions
- * as producing the #QS_QF_ACTIVE_POST trace record, which are:
- * the local filter for this AO ('me->prio') is set
- */
- if ((QS_priv_.locFilter[me->prio >> 3U]
- & (1U << (me->prio & 7U))) != 0U)
- {
- QS_onTestPost((QActive *)0, me, e, true);
- }
- QF_CRIT_X_();
- /* recycle the event immediately, because it was not really posted */
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(e);
- #endif</code>
- </operation>
- </class>
- </package>
- <!--${include}-->
- <directory name="include">
- <!--${include::qassert.h}-->
- <file name="qassert.h">
- <text>/*! @file
- * @brief Customizable and memory-efficient Design by Contract (DbC)
- * for embedded systems
- *
- * @note
- * This header file can be used in C, C++, and mixed C/C++ programs.
- *
- * @note
- * The preprocessor switch #Q_NASSERT disables checking assertions.
- * However, it is generally **not** advisable to disable assertions,
- * **especially** in the production code. Instead, the assertion
- * handler Q_onAssert() should be very carefully designed and tested.
- */
- #ifndef QASSERT_H_
- #define QASSERT_H_
- #ifdef __cplusplus
- extern "C" {
- #endif
- #ifndef Q_NASSERT
- $declare ${DbC::active}
- #else
- $declare ${DbC::inactive}
- #endif
- $declare1 ${DbC}
- #ifdef __cplusplus
- }
- #endif
- #endif /* QASSERT_H_ */</text>
- </file>
- <!--${include::qep.h}-->
- <file name="qep.h">
- <text>/*! @file
- * @brief QEP/C platform-independent public interface.
- *
- * @trace
- * @tr{RQP001}, @tr{RQP101}
- */
- #ifndef QEP_H_
- #define QEP_H_
- /*==========================================================================*/
- /*! The current QP version as an unsigned number
- *
- * @details
- * ::QP_VERSION is a decimal constant, where XX is a 1-digit or 2-digit
- * major version number, Y is a 1-digit minor version number, and Z is
- * a 1-digit release number.
- */
- #define QP_VERSION 722U
- /*! The current QP version as a zero terminated string literal.
- *
- * @details
- * ::QP_VERSION_STR is of the form "XX.Y.Z", where XX is a 1-or 2-digit
- * major version number, Y is a 1-digit minor version number, and Z is
- * a 1-digit release number.
- */
- #define QP_VERSION_STR "7.2.2"
- /*! Encrypted current QP release (7.2.2) and date (2023-03-01) */
- #define QP_RELEASE 0x76BAD85DU
- /*==========================================================================*/
- $declare ${glob-types}
- $declare ${QEP-config}
- /*==========================================================================*/
- $declare ${QEP}
- /*==========================================================================*/
- $declare ${QEP-macros}
- #endif /* QEP_H_ */</text>
- </file>
- <!--${include::qf.h}-->
- <file name="qf.h">
- <text>/*! @file
- * @brief QF/C platform-independent public interface.
- */
- #ifndef QF_H_
- #define QF_H_
- /*==========================================================================*/
- $declare ${QF-config}
- /*==========================================================================*/
- $declare ${QF-types}
- $declare ${QF::QActive}
- $declare ${QF::QActiveVtable}
- $declare ${QF::QMActive}
- $declare ${QF::QMActiveVtable}
- $declare ${QF::QTimeEvt}
- $declare ${QF::QTicker}
- $declare ${QF::QF-base}
- $declare ${QF::QF-dyn}
- $declare ${QF::QF-extern-C}
- /*==========================================================================*/
- $declare ${QF-macros}
- #endif /* QF_H_ */</text>
- </file>
- <!--${include::qf_pkg.h}-->
- <file name="qf_pkg.h">
- <text>/*! @file
- * @brief Internal (package scope) QF/C interface.
- */
- #ifndef QF_PKG_H_
- #define QF_PKG_H_
- /*==========================================================================*/
- $declare ${QF::QF-pkg}
- /*==========================================================================*/
- /* QF-specific critical section */
- #ifndef QF_CRIT_STAT_TYPE
- /*! This is an internal macro for defining the critical section
- * status type. */
- /**
- * @details
- * The purpose of this macro is to enable writing the same code for the
- * case when critical section status type is defined and when it is not.
- * If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
- * provides the definition of the critical section status variable.
- * Otherwise this macro is empty.
- * @sa #QF_CRIT_STAT_TYPE
- */
- #define QF_CRIT_STAT_
- /*! This is an internal macro for entering a critical section. */
- /**
- * @details
- * The purpose of this macro is to enable writing the same code for the
- * case when critical section status type is defined and when it is not.
- * If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
- * invokes QF_CRIT_ENTRY() passing the key variable as the parameter.
- * Otherwise QF_CRIT_ENTRY() is invoked with a dummy parameter.
- * @sa QF_CRIT_ENTRY()
- */
- #define QF_CRIT_E_() QF_CRIT_ENTRY(dummy)
- /*! This is an internal macro for exiting a critical section. */
- /**
- * @details
- * The purpose of this macro is to enable writing the same code for the
- * case when critical section status type is defined and when it is not.
- * If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
- * invokes #QF_CRIT_EXIT passing the key variable as the parameter.
- * Otherwise #QF_CRIT_EXIT is invoked with a dummy parameter.
- * @sa #QF_CRIT_EXIT
- */
- #define QF_CRIT_X_() QF_CRIT_EXIT(dummy)
- #elif (!defined QF_CRIT_STAT_)
- #define QF_CRIT_STAT_ QF_CRIT_STAT_TYPE critStat_;
- #define QF_CRIT_E_() QF_CRIT_ENTRY(critStat_)
- #define QF_CRIT_X_() QF_CRIT_EXIT(critStat_)
- #endif
- /*==========================================================================*/
- /* Assertions inside the critical section */
- #ifdef Q_NASSERT /* Q_NASSERT defined--assertion checking disabled */
- #define Q_ASSERT_CRIT_(id_, test_) ((void)0)
- #define Q_REQUIRE_CRIT_(id_, test_) ((void)0)
- #define Q_ERROR_CRIT_(id_) ((void)0)
- #else /* Q_NASSERT not defined--assertion checking enabled */
- #define Q_ASSERT_CRIT_(id_, test_) do { \
- if ((test_)) {} else { \
- QF_CRIT_X_(); \
- Q_onAssert(&Q_this_module_[0], (int_t)(id_)); \
- } \
- } while (false)
- #define Q_REQUIRE_CRIT_(id_, test_) Q_ASSERT_CRIT_((id_), (test_))
- #define Q_ERROR_CRIT_(id_) do { \
- QF_CRIT_X_(); \
- Q_onAssert(&Q_this_module_[0], (int_t)(id_)); \
- } while (false)
- #endif /* Q_NASSERT */
- /*==========================================================================*/
- /* The following bitmasks are for the fields of the @c refCtr_ attribute
- * of the QTimeEvt struct (inherited from QEvt). This attribute is NOT used
- * for reference counting in time events, because the @c poolId_ attribute
- * is zero ("immutable events").
- */
- #define QTE_IS_LINKED (1U << 7U)
- #define QTE_WAS_DISARMED (1U << 6U)
- #define QTE_TICK_RATE 0x0FU
- /*! @brief structure representing a free block in the Native QF Memory Pool */
- typedef struct QFreeBlock {
- struct QFreeBlock * volatile next;
- } QFreeBlock;
- /* internal helper macros ==================================================*/
- /*! increment the refCtr of a const event (requires casting `const` away)
- * @private @memberof QEvt
- *
- * @trace
- * @tr{PQP11_8}
- */
- static inline void QEvt_refCtr_inc_(QEvt const *me) {
- ++((QEvt *)me)->refCtr_;
- }
- /*! decrement the refCtr of a const event (requires casting `const` away)
- * @private @memberof QEvt
- *
- * @trace
- * @tr{PQP11_8}
- */
- static inline void QEvt_refCtr_dec_(QEvt const *me) {
- --((QEvt *)me)->refCtr_;
- }
- #endif /* QF_PKG_H_ */</text>
- </file>
- <!--${include::qequeue.h}-->
- <file name="qequeue.h">
- <text>/*! @file
- * @brief QP natvie, platform-independent, thread-safe event queue interface
- * @details
- * This header file must be included in all QF ports that use native QF
- * event queue for active objects. Also, this file needs to be included
- * in the QP/C library when the application uses QActive_defer()/
- * QActive_recall(). Finally, this file is also needed when the "raw"
- * thread-safe queues are used for communication between active objects
- * and non-framework entities, such as ISRs, device drivers, or legacy
- * code.
- */
- #ifndef QEQUEUE_H_
- #define QEQUEUE_H_
- #ifndef QF_EQUEUE_CTR_SIZE
- /*! The size [bytes] of the ring-buffer counters used in the
- * native QF event queue implementation. Valid values: 1U, 2U, or 4U;
- * default 1U.
- * @details
- * This macro can be defined in the QF port file (qf_port.h) to
- * configure the ::QEQueueCtr type. Here the macro is not defined so the
- * default of 1 byte is chosen.
- */
- #define QF_EQUEUE_CTR_SIZE 1U
- #endif
- #if (QF_EQUEUE_CTR_SIZE == 1U)
- /*! The data type to store the ring-buffer counters based on
- * the macro #QF_EQUEUE_CTR_SIZE.
- * @details
- * The dynamic range of this data type determines the maximum length
- * of the ring buffer managed by the native QF event queue.
- */
- typedef uint8_t QEQueueCtr;
- #elif (QF_EQUEUE_CTR_SIZE == 2U)
- typedef uint16_t QEQueueCtr;
- #elif (QF_EQUEUE_CTR_SIZE == 4U)
- typedef uint32_t QEQueueCtr;
- #else
- #error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U"
- #endif
- /*==========================================================================*/
- $declare ${QF::QEQueue}
- #endif /* QEQUEUE_H_ */</text>
- </file>
- <!--${include::qmpool.h}-->
- <file name="qmpool.h">
- <text>/*! @file
- * @brief QP native, platform-independent memory pool ::QMPool interface.
- */
- #ifndef QMPOOL_H_
- #define QMPOOL_H_
- /*==========================================================================*/
- #ifndef QF_MPOOL_SIZ_SIZE
- /*! macro to override the default ::QMPoolSize size [bytes].
- * Valid values 1U, 2U, or 4U; default 2U
- */
- #define QF_MPOOL_SIZ_SIZE 2U
- #endif
- #if (QF_MPOOL_SIZ_SIZE == 1U)
- /*! The data type to store the block-size based on the macro
- * #QF_MPOOL_SIZ_SIZE.
- * @details
- * The dynamic range of this data type determines the maximum size
- * of blocks that can be managed by the native QF event pool.
- */
- typedef uint8_t QMPoolSize;
- #elif (QF_MPOOL_SIZ_SIZE == 2U)
- typedef uint16_t QMPoolSize;
- #elif (QF_MPOOL_SIZ_SIZE == 4U)
- typedef uint32_t QMPoolSize;
- #else
- #error "QF_MPOOL_SIZ_SIZE defined incorrectly, expected 1U, 2U, or 4U"
- #endif
- /*==========================================================================*/
- #ifndef QF_MPOOL_CTR_SIZE
- /*! macro to override the default ::QMPoolCtr size [bytes].
- * Valid values 1U, 2U, or 4U; default 2U
- */
- #define QF_MPOOL_CTR_SIZE 2U
- #endif
- #if (QF_MPOOL_CTR_SIZE == 1U)
- /*! The data type to store the block-counter based on the macro
- * #QF_MPOOL_CTR_SIZE.
- * @details
- * The dynamic range of this data type determines the maximum number
- * of blocks that can be stored in the pool.
- */
- typedef uint8_t QMPoolCtr;
- #elif (QF_MPOOL_CTR_SIZE == 2U)
- typedef uint16_t QMPoolCtr;
- #elif (QF_MPOOL_CTR_SIZE == 4U)
- typedef uint32_t QMPoolCtr;
- #else
- #error "QF_MPOOL_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U"
- #endif
- /*! Memory pool element to allocate correctly aligned storage
- * for QMPool class.
- * @param[in] evType_ event type (name of the subclass of QEvt)
- */
- #define QF_MPOOL_EL(evType_) \
- struct { void *sto_[((sizeof(evType_) - 1U)/sizeof(void*)) + 1U]; }
- /*==========================================================================*/
- $declare ${QF::QMPool}
- #endif /* QMPOOL_H_ */</text>
- </file>
- <!--${include::qv.h}-->
- <file name="qv.h">
- <text>/*! @file
- * @brief QV/C (cooperative "Vanilla" kernel) platform-independent
- * public interface
- */
- #ifndef QV_H_
- #define QV_H_
- /*==========================================================================*/
- /* QF customization for QV -- data members of the QActive class... */
- /* QV event-queue used for AOs */
- #define QF_EQUEUE_TYPE QEQueue
- /*==========================================================================*/
- #include "qequeue.h" /* QV kernel uses the native QP event queue */
- #include "qmpool.h" /* QV kernel uses the native QP memory pool */
- #include "qf.h" /* QF framework integrates directly with QV */
- //============================================================================
- $declare ${QV::QV-base}
- /*==========================================================================*/
- /* interface used only inside QF, but not in applications */
- #ifdef QP_IMPL
- /* QV-specific scheduler locking and event queue... */
- $declare ${QV-impl}
- /* Native QF event pool operations... */
- $declare ${QF-QMPool-impl}
- #endif /* QP_IMPL */
- #endif /* QV_H_ */</text>
- </file>
- <!--${include::qk.h}-->
- <file name="qk.h">
- <text>/*! @file
- * @brief QK/C (preemptive non-blocking kernel) platform-independent
- * public interface.
- */
- #ifndef QK_H_
- #define QK_H_
- /*==========================================================================*/
- /* QF configuration for QK -- data members of the QActive class... */
- /* QK event-queue used for AOs */
- #define QF_EQUEUE_TYPE QEQueue
- /* QK thread type used for AOs
- * QK uses this member to store the private Thread-Local Storage pointer.
- */
- #define QF_THREAD_TYPE void*
- #include "qequeue.h" /* QK kernel uses the native QP event queue */
- #include "qmpool.h" /* QK kernel uses the native QP memory pool */
- #include "qf.h" /* QF framework integrates directly with QK */
- /*==========================================================================*/
- $declare ${QK::QK-extern-C}
- /*--------------------------------------------------------------------------*/
- $declare ${QK::QK-base}
- /*==========================================================================*/
- /* interface used only inside QF, but not in applications */
- #ifdef QP_IMPL
- /* QK-specific scheduler locking and event queue... */
- $declare ${QK-impl}
- /* Native QF event pool operations... */
- $declare ${QF-QMPool-impl}
- #endif /* QP_IMPL */
- #endif /* QK_H_ */</text>
- </file>
- <!--${include::qxk.h}-->
- <file name="qxk.h">
- <text>/*! @file
- * @brief QXK/C (preemptive dual-mode kernel) platform-independent
- * public interface.
- */
- #ifndef QXK_H_
- #define QXK_H_
- /*==========================================================================*/
- /* QF configuration for QXK -- data members of the QActive class... */
- /* QXK event-queue used for AOs */
- #define QF_EQUEUE_TYPE QEQueue
- /* QXK OS-object used to store the private stack pointer for extended threads.
- * (The private stack pointer is NULL for basic-threads).
- */
- #define QF_OS_OBJECT_TYPE void*
- /* QXK thread type used to store the private Thread-Local Storage pointer */
- #define QF_THREAD_TYPE void*
- /*! Access Thread-Local Storage (TLS) and cast it on the given `type_` */
- #define QXK_TLS(type_) ((type_)QXK_current()->thread)
- /*==========================================================================*/
- #include "qequeue.h" /* QXK kernel uses the native QP event queue */
- #include "qmpool.h" /* QXK kernel uses the native QP memory pool */
- #include "qf.h" /* QF framework integrates directly with QXK */
- /*==========================================================================*/
- $declare ${QXK::QXK-extern-C}
- /*--------------------------------------------------------------------------*/
- $declare ${QXK::QXK-base}
- $declare ${QXK::QXThread}
- $declare ${QXK::QXThreadVtable}
- $declare ${QXK::QXSemaphore}
- $declare ${QXK::QXMutex}
- $declare ${QXK-macros}
- /*==========================================================================*/
- /* interface used only inside QP implementation, but not in applications */
- #ifdef QP_IMPL
- /* QXK implementation... */
- $declare ${QXK-impl}
- /* Native QF event pool operations... */
- $declare ${QF-QMPool-impl}
- #endif /* QP_IMPL */
- #endif /* QXK_H_ */</text>
- </file>
- <!--${include::qs.h}-->
- <file name="qs.h">
- <text>/*! @file
- * @brief QS/C platform-independent public interface.
- */
- #ifndef QS_H_
- #define QS_H_
- #ifndef Q_SPY
- #error "Q_SPY must be defined to include qs.h"
- #endif
- /*==========================================================================*/
- $declare ${QS-config}
- /*==========================================================================*/
- $declare ${QS}
- /*==========================================================================*/
- $declare ${QS-macros}
- /*==========================================================================*/
- /* Facilities for QS critical section */
- /* QS-specific critical section */
- #ifdef QS_CRIT_ENTRY /* separate QS critical section defined? */
- #ifndef QS_CRIT_STAT_TYPE
- #define QS_CRIT_STAT_
- #define QS_CRIT_E_() QS_CRIT_ENTRY(dummy)
- #define QS_CRIT_X_() QS_CRIT_EXIT(dummy); QS_REC_DONE()
- #else
- #define QS_CRIT_STAT_ QS_CRIT_STAT_TYPE critStat_;
- #define QS_CRIT_E_() QS_CRIT_ENTRY(critStat_)
- #define QS_CRIT_X_() QS_CRIT_EXIT(critStat_); QS_REC_DONE()
- #endif /* QS_CRIT_STAT_TYPE */
- #else /* separate QS critical section not defined--use the QF definition */
- #ifndef QF_CRIT_STAT_TYPE
- /*! This is an internal macro for defining the critical section
- * status type.
- * @details
- * The purpose of this macro is to enable writing the same code for the
- * case when critical section status type is defined and when it is not.
- * If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
- * provides the definition of the critical section status variable.
- * Otherwise this macro is empty.
- * @sa #QF_CRIT_STAT_TYPE
- */
- #define QS_CRIT_STAT_
- /*! This is an internal macro for entering a critical section.
- * @details
- * The purpose of this macro is to enable writing the same code for the
- * case when critical section status type is defined and when it is not.
- * If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
- * invokes QF_CRIT_ENTRY() passing the key variable as the parameter.
- * Otherwise QF_CRIT_ENTRY() is invoked with a dummy parameter.
- * @sa QF_CRIT_ENTRY()
- */
- #define QS_CRIT_E_() QF_CRIT_ENTRY(dummy)
- /*! This is an internal macro for exiting a critical section.
- * @details
- * The purpose of this macro is to enable writing the same code for the
- * case when critical section status type is defined and when it is not.
- * If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
- * invokes QF_CRIT_EXIT() passing the key variable as the parameter.
- * Otherwise QF_CRIT_EXIT() is invoked with a dummy parameter.
- * @sa QF_CRIT_EXIT()
- */
- #define QS_CRIT_X_() QF_CRIT_EXIT(dummy); QS_REC_DONE()
- #elif (!defined QS_CRIT_STAT_)
- #define QS_CRIT_STAT_ QF_CRIT_STAT_TYPE critStat_;
- #define QS_CRIT_E_() QF_CRIT_ENTRY(critStat_)
- #define QS_CRIT_X_() QF_CRIT_EXIT(critStat_); QS_REC_DONE()
- #endif /* simple unconditional interrupt disabling used */
- #endif /* separate QS critical section not defined */
- /*==========================================================================*/
- /* Macros for use in QUTest only */
- #ifdef Q_UTEST
- $declare ${QUTest}
- /*--------------------------------------------------------------------------*/
- /* QP-stub for QUTest
- * NOTE: The QP-stub is needed for unit testing QP applications,
- * but might NOT be needed for testing QP itself.
- */
- #if Q_UTEST != 0
- $declare ${QUTest-stub::QS}
- $declare ${QUTest-stub::QHsmDummy}
- $declare ${QUTest-stub::QActiveDummy}
- #endif /* Q_UTEST != 0 */
- /*! QS macro to define the Test-Probe for a given `fun_` */
- #define QS_TEST_PROBE_DEF(fun_) \
- uint32_t const qs_tp_ = QS_getTestProbe_((void (*)(void))(fun_));
- /*! QS macro to apply a Test-Probe */
- #define QS_TEST_PROBE(code_) \
- if (qs_tp_ != 0U) { code_ }
- /*! QS macro to apply a Test-Probe */
- #define QS_TEST_PROBE_ID(id_, code_) \
- if (qs_tp_ == (uint32_t)(id_)) { code_ }
- /*! QS macro to pause test execution and enter the test event-loop */
- #define QS_TEST_PAUSE() (QS_test_pause_())
- #else /* Q_UTEST not defined */
- /* dummy definitions when not building for QUTEST */
- #define QS_TEST_PROBE_DEF(fun_)
- #define QS_TEST_PROBE(code_)
- #define QS_TEST_PROBE_ID(id_, code_)
- #define QS_TEST_PAUSE() ((void)0)
- #endif /* Q_UTEST */
- #endif /* QS_H_ */</text>
- </file>
- <!--${include::qs_dummy.h}-->
- <file name="qs_dummy.h">
- <text>/*! @file
- * @brief Dummy definitions of the QS macros that avoid code generation from
- * the QS instrumentation.
- */
- #ifndef QS_DUMMY_H_
- #define QS_DUMMY_H_
- #ifdef Q_SPY
- #error "Q_SPY must NOT be defined to include qs_dummy.h"
- #endif
- #define QS_INIT(arg_) ((uint8_t)1U)
- #define QS_EXIT() ((void)0)
- #define QS_DUMP() ((void)0)
- #define QS_GLB_FILTER(rec_) ((void)0)
- #define QS_LOC_FILTER(qs_id_) ((void)0)
- #define QS_GET_BYTE(pByte_) ((uint16_t)0xFFFFU)
- #define QS_GET_BLOCK(pSize_) ((uint8_t *)0)
- #define QS_BEGIN_ID(rec_, qs_id_) if (false) {
- #define QS_END() }
- #define QS_BEGIN_NOCRIT(rec_, qs_id_) if (false) {
- #define QS_END_NOCRIT() }
- #define QS_I8(width_, data_) ((void)0)
- #define QS_U8(width_, data_) ((void)0)
- #define QS_I16(width_, data_) ((void)0)
- #define QS_U16(width_, data_) ((void)0)
- #define QS_I32(width_, data_) ((void)0)
- #define QS_U32(width_, data_) ((void)0)
- #define QS_F32(width_, data_) ((void)0)
- #define QS_F64(width_, data_) ((void)0)
- #define QS_I64(width_, data_) ((void)0)
- #define QS_U64(width_, data_) ((void)0)
- #define QS_ENUM(group_, value_) ((void)0)
- #define QS_STR(str_) ((void)0)
- #define QS_MEM(mem_, size_) ((void)0)
- #define QS_SIG(sig_, obj_) ((void)0)
- #define QS_OBJ(obj_) ((void)0)
- #define QS_FUN(fun_) ((void)0)
- #define QS_SIG_DICTIONARY(sig_, obj_) ((void)0)
- #define QS_OBJ_DICTIONARY(obj_) ((void)0)
- #define QS_OBJ_ARR_DICTIONARY(obj_, idx_) ((void)0)
- #define QS_FUN_DICTIONARY(fun_) ((void)0)
- #define QS_USR_DICTIONARY(rec_) ((void)0)
- #define QS_ENUM_DICTIONARY(value_, group_) ((void)0)
- #define QS_ASSERTION(module_, loc_, delay_) ((void)0)
- #define QS_FLUSH() ((void)0)
- #define QS_TEST_PROBE_DEF(fun_)
- #define QS_TEST_PROBE(code_)
- #define QS_TEST_PROBE_ID(id_, code_)
- #define QS_TEST_PAUSE() ((void)0)
- #define QS_OUTPUT() ((void)0)
- #define QS_RX_INPUT() ((void)0)
- /*==========================================================================*/
- /* internal QS macros used only in the QP components */
- #ifdef QP_IMPL
- /* predefined QS trace records */
- #define QS_BEGIN_PRE_(rec_, qs_id_) if (false) {
- #define QS_END_PRE_() }
- #define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_) if (false) {
- #define QS_END_NOCRIT_PRE_() }
- #define QS_U8_PRE_(data_) ((void)0)
- #define QS_2U8_PRE_(data1_, data2_) ((void)0)
- #define QS_U16_PRE_(data_) ((void)0)
- #define QS_U32_PRE_(data_) ((void)0)
- #define QS_TIME_PRE_() ((void)0)
- #define QS_SIG_PRE_(sig_) ((void)0)
- #define QS_EVS_PRE_(size_) ((void)0)
- #define QS_OBJ_PRE_(obj_) ((void)0)
- #define QS_FUN_PRE_(fun_) ((void)0)
- #define QS_EQC_PRE_(ctr_) ((void)0)
- #define QS_MPC_PRE_(ctr_) ((void)0)
- #define QS_MPS_PRE_(size_) ((void)0)
- #define QS_TEC_PRE_(ctr_) ((void)0)
- #define QS_CRIT_STAT_
- #define QF_QS_CRIT_ENTRY() ((void)0)
- #define QF_QS_CRIT_EXIT() ((void)0)
- #define QF_QS_ISR_ENTRY(isrnest_, prio_) ((void)0)
- #define QF_QS_ISR_EXIT(isrnest_, prio_) ((void)0)
- #define QF_QS_ACTION(act_) ((void)0)
- #endif /* QP_IMPL */
- #endif /* QS_DUMMY_H_ */</text>
- </file>
- <!--${include::qs_pkg.h}-->
- <file name="qs_pkg.h">
- <text>/*! @file
- * @brief Internal (package scope) QS/C interface.
- */
- #ifndef QS_PKG_H_
- #define QS_PKG_H_
- /*==========================================================================*/
- /*! QS received record types (RX channel)
- * @details
- * This enumeration specifies the record types for the QS receive channel
- */
- enum QSpyRxRecords {
- QS_RX_INFO, /*!< query Target info (ver, config, tstamp) */
- QS_RX_COMMAND, /*!< execute a user-defined command in the Target */
- QS_RX_RESET, /*!< reset the Target */
- QS_RX_TICK, /*!< call QTIMEEVT_TICK_X() in the Target */
- QS_RX_PEEK, /*!< peek Target memory */
- QS_RX_POKE, /*!< poke Target memory */
- QS_RX_FILL, /*!< fill Target memory */
- QS_RX_TEST_SETUP, /*!< test setup */
- QS_RX_TEST_TEARDOWN, /*!< test teardown */
- QS_RX_TEST_PROBE, /*!< set a Test-Probe in the Target */
- QS_RX_GLB_FILTER, /*!< set global filters in the Target */
- QS_RX_LOC_FILTER, /*!< set local filters in the Target */
- QS_RX_AO_FILTER, /*!< set local AO filter in the Target */
- QS_RX_CURR_OBJ, /*!< set the "current-object" in the Target */
- QS_RX_TEST_CONTINUE, /*!< continue a test after QS_TEST_PAUSE() */
- QS_RX_QUERY_CURR, /*!< query the "current object" in the Target */
- QS_RX_EVENT /*!< inject an event to the Target */
- };
- /*==========================================================================*/
- /*! Frame character of the QS output protocol */
- #define QS_FRAME (0x7EU)
- /*! Escape character of the QS output protocol */
- #define QS_ESC (0x7DU)
- /*! The expected checksum value over a correct QS record */
- #define QS_GOOD_CHKSUM (0xFFU)
- /*! Escape modifier of the QS output protocol */
- /**
- * @details
- * The escaped byte is XOR-ed with the escape modifier before it is inserted
- * into the QS buffer.
- */
- #define QS_ESC_XOR (0x20U)
- /*==========================================================================*/
- /*! Internal QS macro to begin a predefined QS record with
- * entering critical section.
- *
- * @note This macro is intended to use only inside QP components and NOT
- * at the application level.
- * @sa QS_BEGIN_ID()
- */
- #define QS_BEGIN_PRE_(rec_, qs_id_) \
- if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \
- QS_CRIT_E_(); \
- QS_beginRec_((uint_fast8_t)(rec_));
- /*! Internal QS macro to end a predefined QS record with
- * exiting critical section.
- *
- * @note This macro is intended to use only inside QP components and NOT
- * at the application level.
- * @sa QS_END()
- */
- #define QS_END_PRE_() \
- QS_endRec_(); \
- QS_CRIT_X_(); \
- }
- /*! Internal macro to begin a predefined QS record without
- * entering critical section.
- *
- * @note This macro is intended to use only inside QP components and NOT
- * at the application level.
- * @sa QS_BEGIN_NOCRIT()
- */
- #define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_) \
- if (QS_GLB_CHECK_(rec_) && QS_LOC_CHECK_(qs_id_)) { \
- QS_beginRec_((uint_fast8_t)(rec_));
- /*! Internal QS macro to end a predefined QS record without
- * exiting critical section
- *
- * @note This macro is intended to use only inside QP components and NOT
- * at the application level. @sa #QS_END_NOCRIT
- */
- #define QS_END_NOCRIT_PRE_() QS_endRec_(); }
- /*! Internal QS macro to output a predefined uint8_t data element */
- #define QS_U8_PRE_(data_) (QS_u8_raw_((uint8_t)(data_)))
- /*! Internal QS macro to output 2 predefined uint8_t data elements */
- #define QS_2U8_PRE_(data1_, data2_) \
- (QS_2u8_raw_((uint8_t)(data1_), (uint8_t)(data2_)))
- /*! Internal QS macro to output an predefined uint16_t data element */
- #define QS_U16_PRE_(data_) (QS_u16_raw_((uint16_t)(data_)))
- /*! Internal QS macro to output a predefined uint32_t data element */
- #define QS_U32_PRE_(data_) (QS_u32_raw_((uint32_t)(data_)))
- /*! Internal QS macro to output a predefined zero-terminated string element */
- #define QS_STR_PRE_(msg_) (QS_str_raw_((msg_)))
- #if (!defined Q_SIGNAL_SIZE || (Q_SIGNAL_SIZE == 1U))
- /*! Internal macro to output an unformatted event signal data element */
- /**
- * @note the size of the pointer depends on the macro #Q_SIGNAL_SIZE.
- */
- #define QS_SIG_PRE_(sig_) (QS_u8_raw_((uint8_t)sig_))
- #elif (Q_SIGNAL_SIZE == 2U)
- #define QS_SIG_PRE_(sig_) (QS_u16_raw_((uint16_t)sig_))
- #elif (Q_SIGNAL_SIZE == 4U)
- #define QS_SIG_PRE_(sig_) (QS_u32_raw_((uint32_t)sig_))
- #endif
- #define QS_OBJ_PRE_(obj_) (QS_obj_raw_(obj_))
- #if (!defined QS_FUN_PTR_SIZE || (QS_FUN_PTR_SIZE == 1U))
- #define QS_FUN_PRE_(fun_) (QS_u8_raw_((uint8_t)(fun_)))
- #elif (QS_FUN_PTR_SIZE == 2U)
- #define QS_FUN_PRE_(fun_) (QS_u16_raw_((uint16_t)(fun_)))
- #elif (QS_FUN_PTR_SIZE == 4U)
- #define QS_FUN_PRE_(fun_) (QS_u32_raw_((uint32_t)(fun_)))
- #elif (QS_FUN_PTR_SIZE == 8U)
- #define QS_FUN_PRE_(fun_) (QS_u64_raw_((uint64_t)(fun_)))
- #else
- /*! Internal macro to output an unformatted function pointer */
- /** @note the size of the pointer depends on the macro #QS_FUN_PTR_SIZE.
- * If the size is not defined the size of pointer is assumed 4-bytes.
- */
- #define QS_FUN_PRE_(fun_) (QS_u32_raw_((uint32_t)(fun_)))
- #endif
- /*==========================================================================*/
- #if (!defined QF_EQUEUE_CTR_SIZE || (QF_EQUEUE_CTR_SIZE == 1U))
- /*! Internal QS macro to output an unformatted event queue counter
- * data element. */
- /**
- * @note the counter size depends on the macro #QF_EQUEUE_CTR_SIZE.
- */
- #define QS_EQC_PRE_(ctr_) QS_u8_raw_((uint8_t)(ctr_))
- #elif (QF_EQUEUE_CTR_SIZE == 2U)
- #define QS_EQC_PRE_(ctr_) QS_u16_raw_((uint16_t)(ctr_))
- #elif (QF_EQUEUE_CTR_SIZE == 4U)
- #define QS_EQC_PRE_(ctr_) QS_u32_raw_((uint32_t)(ctr_))
- #endif
- #if (!defined QF_EVENT_SIZ_SIZE || (QF_EVENT_SIZ_SIZE == 1U))
- /*! Internal QS macro to output an unformatted event size
- * data element. */
- /**
- * @note the event size depends on the macro #QF_EVENT_SIZ_SIZE.
- */
- #define QS_EVS_PRE_(size_) QS_u8_raw_((uint8_t)(size_))
- #elif (QF_EVENT_SIZ_SIZE == 2U)
- #define QS_EVS_PRE_(size_) QS_u16_raw_((uint16_t)(size_))
- #elif (QF_EVENT_SIZ_SIZE == 4U)
- #define QS_EVS_PRE_(size_) QS_u32_raw_((uint32_t)(size_))
- #endif
- #if (!defined QF_MPOOL_SIZ_SIZE || (QF_MPOOL_SIZ_SIZE == 1U))
- /*! Internal QS macro to output an unformatted memory pool
- * block-size data element */
- /**
- * @note the block-size depends on the macro #QF_MPOOL_SIZ_SIZE.
- */
- #define QS_MPS_PRE_(size_) QS_u8_raw_((uint8_t)(size_))
- #elif (QF_MPOOL_SIZ_SIZE == 2U)
- #define QS_MPS_PRE_(size_) QS_u16_raw_((uint16_t)(size_))
- #elif (QF_MPOOL_SIZ_SIZE == 4U)
- #define QS_MPS_PRE_(size_) QS_u32_raw_((uint32_t)(size_))
- #endif
- #if (!defined QF_MPOOL_CTR_SIZE || (QF_MPOOL_CTR_SIZE == 1U))
- /*! Internal QS macro to output an unformatted memory pool
- * block-counter data element. */
- /**
- * @note the counter size depends on the macro #QF_MPOOL_CTR_SIZE.
- */
- #define QS_MPC_PRE_(ctr_) QS_u8_raw_((uint8_t)(ctr_))
- #elif (QF_MPOOL_CTR_SIZE == 2U)
- #define QS_MPC_PRE_(ctr_) QS_u16_raw_((uint16_t)(ctr_))
- #elif (QF_MPOOL_CTR_SIZE == 4U)
- #define QS_MPC_PRE_(ctr_) QS_u32_raw_((uint16_t)(ctr_))
- #endif
- #if (!defined QF_TIMEEVT_CTR_SIZE || (QF_TIMEEVT_CTR_SIZE == 1U))
- /*! Internal QS macro to output an unformatted time event
- * tick-counter data element */
- /**
- * @note the counter size depends on the macro #QF_TIMEEVT_CTR_SIZE.
- */
- #define QS_TEC_PRE_(ctr_) QS_u8_raw_((uint8_t)(ctr_))
- #elif (QF_TIMEEVT_CTR_SIZE == 2U)
- #define QS_TEC_PRE_(ctr_) QS_u16_raw_((uint16_t)(ctr_))
- #elif (QF_TIMEEVT_CTR_SIZE == 4U)
- #define QS_TEC_PRE_(ctr_) QS_u32_raw_((uint32_t)(ctr_))
- #endif
- /*==========================================================================*/
- /*! Internal QS macro to insert an un-escaped byte into the QS buffer */
- #define QS_INSERT_BYTE_(b_) \
- buf[head] = (b_); \
- ++head; \
- if (head == end) { \
- head = 0U; \
- }
- /*! Internal QS macro to insert an escaped byte into the QS buffer */
- #define QS_INSERT_ESC_BYTE_(b_) \
- chksum = (uint8_t)(chksum + (b_)); \
- if (((b_) != QS_FRAME) && ((b_) != QS_ESC)) { \
- QS_INSERT_BYTE_(b_) \
- } \
- else { \
- QS_INSERT_BYTE_(QS_ESC) \
- QS_INSERT_BYTE_((uint8_t)((b_) ^ QS_ESC_XOR))\
- ++QS_priv_.used; \
- }
- #endif /* QS_PKG_H_ */</text>
- </file>
- <!--${include::qpc.h}-->
- <file name="qpc.h">
- <text>/*! @file
- * @brief QP/C public interface including backwards-compatibility layer
- * @details
- * This header file must be included directly or indirectly
- * in all application modules (*.c files) that use QP/C.
- */
- #ifndef QPC_H_
- #define QPC_H_
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*==========================================================================*/
- #include "qf_port.h" /* QF/C port from the port directory */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* software tracing enabled? */
- #include "qs_port.h" /* QS/C port from the port directory */
- #else
- #include "qs_dummy.h" /* QS/C dummy (inactive) interface */
- #endif
- /*==========================================================================*/
- #ifndef QP_API_VERSION
- /*! Specifies the backwards compatibility with the QP/C API version.
- * @details
- * For example, QP_API_VERSION==691 will cause generating the compatibility
- * layer with QP/C version 6.9.1 and newer, but not older than 6.9.1.
- * QP_API_VERSION==0 causes generation of the maximum currently supported
- * backwards compatibility. This is the default.<br>
- * <br>
- * Conversely, QP_API_VERSION==9999 means that no compatibility layer should
- * be generated. This setting is useful for checking if an application
- * complies with the latest QP/C API.
- */
- #define QP_API_VERSION 0
- #endif /* #ifndef QP_API_VERSION */
- /*==========================================================================*/
- /* QP API compatibility layer... */
- #if (QP_API_VERSION < 700)
- /*! @deprecated plain 'char' is no longer forbidden in MISRA-C 2012 */
- typedef char char_t;
- /*! Static (compile-time) assertion.
- *
- * @deprecated
- * Use Q_ASSERT_STATIC() or better yet `_Static_assert()` instead.
- */
- #define Q_ASSERT_COMPILE(expr_) Q_ASSERT_STATIC(expr_)
- /*==========================================================================*/
- #if (QP_API_VERSION < 691)
- /*! @deprecated enable the QS global filter */
- #define QS_FILTER_ON(rec_) QS_GLB_FILTER((rec_))
- /*! @deprecated disable the QS global filter */
- #define QS_FILTER_OFF(rec_) QS_GLB_FILTER(-(rec_))
- /*! @deprecated enable the QS local filter for SM (state machine) object */
- #define QS_FILTER_SM_OBJ(obj_) ((void)0)
- /*! @deprecated enable the QS local filter for AO (active objects) */
- #define QS_FILTER_AO_OBJ(obj_) ((void)0)
- /*! @deprecated enable the QS local filter for MP (memory pool) object */
- #define QS_FILTER_MP_OBJ(obj_) ((void)0)
- /*! @deprecated enable the QS local filter for EQ (event queue) object */
- #define QS_FILTER_EQ_OBJ(obj_) ((void)0)
- /*! @deprecated enable the QS local filter for TE (time event) object */
- #define QS_FILTER_TE_OBJ(obj_) ((void)0)
- #ifdef Q_SPY
- /*! @deprecated local Filter for a generic application object `obj_`. */
- #define QS_FILTER_AP_OBJ(obj_) (QS_priv_.locFilter_AP = (obj_))
- /*! @deprecated begin of a user QS record, instead use QS_BEGIN_ID() */
- #define QS_BEGIN(rec_, obj_) \
- if (((QS_priv_.glbFilter[(uint_fast8_t)(rec_) >> 3U] \
- & (1U << ((uint_fast8_t)(rec_) & 7U))) != 0U) \
- && ((QS_priv_.locFilter_AP == (void *)0) \
- || (QS_priv_.locFilter_AP == (obj_)))) \
- { \
- QS_CRIT_STAT_ \
- QS_CRIT_E_(); \
- QS_beginRec_((uint_fast8_t)(rec_)); \
- QS_TIME_PRE_(); {
- /*! @deprecated Output formatted uint32_t to the QS record */
- #define QS_U32_HEX(width_, data_) \
- (QS_u32_fmt_((uint8_t)(((width_) << 4)) | QS_HEX_FMT, (data_)))
- #else
- #define QS_FILTER_AP_OBJ(obj_) ((void)0)
- #define QS_BEGIN(rec_, obj_) if (false) {
- #define QS_U32_HEX(width_, data_) ((void)0)
- #endif
- /*==========================================================================*/
- #if (QP_API_VERSION < 660)
- /*! @deprecated casting to QXThreadHandler
- * instead use: the new signature of QXThreadHandler and don't cast
- */
- #define Q_XTHREAD_CAST(handler_) ((QXThreadHandler)(handler_))
- /*==========================================================================*/
- #if (QP_API_VERSION < 580)
- /*! @deprecated call to the QMSM_INIT() operation; instead use: QHSM_INIT() */
- #define QMSM_INIT(me_, e_) QHSM_INIT((me_), (e_))
- /*! @deprecated call to the QMSM_DISPATCH() operation;
- * instead use: QHSM_DISPATCH() */
- #define QMSM_DISPATCH(me_, e_) QHSM_DISPATCH((me_), (e_), 0U)
- #endif /* QP_API_VERSION < 580 */
- #endif /* QP_API_VERSION < 660 */
- #endif /* QP_API_VERSION < 691 */
- #endif /* QP_API_VERSION < 700 */
- #ifdef __cplusplus
- }
- #endif
- #endif /* QPC_H_ */</text>
- </file>
- <!--${include::qstamp.h}-->
- <file name="qstamp.h">
- <text>/*! @file
- * @brief Application build time-stamp interface
- */
- #ifndef QSTAMP_H_
- #define QSTAMP_H_
- extern char const Q_BUILD_DATE[12];
- extern char const Q_BUILD_TIME[9];
- #endif /* QSTAMP_H_ */</text>
- </file>
- </directory>
- <!--${src}-->
- <directory name="src">
- <!--${src::qf}-->
- <directory name="qf">
- <!--${src::qf::qep_hsm.c}-->
- <file name="qep_hsm.c">
- <text>/*! @file
- * @brief ::QHsm implementation
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qep_port.h" /* QEP port */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- Q_DEFINE_THIS_MODULE("qep_hsm")
- /*==========================================================================*/
- $define ${QEP::QP_versionStr[8]}
- /*! Immutable events corresponding to the reserved signals.
- *
- * @details
- * Static, immutable reserved events that the QEP event processor sends
- * to state handler functions of QHsm-style state machine to execute entry
- * actions, exit actions, and initial transitions.
- */
- static QEvt const l_reservedEvt_[] = {
- { (QSignal)Q_EMPTY_SIG, 0U, 0U },
- { (QSignal)Q_ENTRY_SIG, 0U, 0U },
- { (QSignal)Q_EXIT_SIG, 0U, 0U },
- { (QSignal)Q_INIT_SIG, 0U, 0U }
- };
- /*! helper function to trigger reserved event in an QHsm
- * @private @memberof QHsm
- *
- * @param[in] state state handler function
- * @param[in] sig reserved signal to trigger
- */
- static inline QState QHsm_reservedEvt_(
- QHsm * const me,
- QStateHandler const state,
- enum QReservedSig const sig)
- {
- return (*state)(me, &l_reservedEvt_[sig]);
- }
- /*! maximum depth of state nesting in a HSM (including the top level),
- * must be >= 3
- */
- enum { QHSM_MAX_NEST_DEPTH_ = 6};
- $define ${QEP::QHsm}</text>
- </file>
- <!--${src::qf::qep_msm.c}-->
- <file name="qep_msm.c">
- <text>#define QP_IMPL /* this is QP implementation */
- #include "qep_port.h" /* QEP port */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- Q_DEFINE_THIS_MODULE("qep_msm")
- /*==========================================================================*/
- /*! internal QEP constants */
- /*! top state object for QMsm-style state machines. */
- static struct QMState const l_msm_top_s = {
- (struct QMState *)0,
- Q_STATE_CAST(0),
- Q_ACTION_CAST(0),
- Q_ACTION_CAST(0),
- Q_ACTION_CAST(0)
- };
- /*! maximum depth of entry levels in a MSM for transition to history. */
- enum { QMSM_MAX_ENTRY_DEPTH_ = 4};
- /*==========================================================================*/
- $define ${QEP::QMsm}</text>
- </file>
- <!--${src::qf::qf_act.c}-->
- <file name="qf_act.c">
- <text>/*! @file
- * @brief Empty file kept only for backwards compatibility.
- *
- * @deprecated please stop using this file.
- *
- * @sa qf_qact.c
- */
- extern char const dummy; /* declaration */
- char const dummy = '\0'; /* definition */</text>
- </file>
- <!--${src::qf::qf_actq.c}-->
- <file name="qf_actq.c">
- <text>/*! @file
- * @brief ::QActive native queue operations (based on ::QEQueue)
- *
- * @note
- * This `qf_actq.c` source file needs to be included in the application
- * build only when the native ::QEQueue queue is used for ::QActive objects
- * (instead of a message queue of an RTOS).
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- Q_DEFINE_THIS_MODULE("qf_actq")
- /*==========================================================================*/
- $define ${QF::QActive::post_}
- $define ${QF::QActive::postLIFO_}
- $define ${QF::QActive::get_}
- $define ${QF::QF-base::getQueueMin}
- /*==========================================================================*/
- /*! Perform downcast to QTicker pointer.
- *
- * @details
- * This macro encapsulates the downcast to (QTicker *), which is used in
- * QTicker_init_() and QTicker_dispatch_(). Such casts violate MISRA-C 2012
- * Rule 11.3(req) "cast from pointer to object type to pointer to different
- * object type".
- */
- #define QTICKER_CAST_(me_) ((QActive *)(me_))
- $define ${QF::QTicker}</text>
- </file>
- <!--${src::qf::qf_defer.c}-->
- <file name="qf_defer.c">
- <text>/*! @file
- * @brief QActive_defer() and QActive_recall() implementation.
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- Q_DEFINE_THIS_MODULE("qf_defer")
- $define ${QF::QActive::defer}
- $define ${QF::QActive::recall}
- $define ${QF::QActive::flushDeferred}</text>
- </file>
- <!--${src::qf::qf_dyn.c}-->
- <file name="qf_dyn.c">
- <text>/*! @file
- * @brief QF/C dynamic event management
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- #if (QF_MAX_EPOOL > 0U) /* dynamic events configured? */
- Q_DEFINE_THIS_MODULE("qf_dyn")
- //============================================================================
- $define ${QF::QF-pkg::maxPool_}
- $define ${QF::QF-pkg::ePool_[QF_MAX_EPOOL]}
- //============================================================================
- $define ${QEP::QEvt}
- //============================================================================
- $define ${QF::QF-dyn}
- #endif /* (QF_MAX_EPOOL > 0U) dynamic events configured */</text>
- </file>
- <!--${src::qf::qf_mem.c}-->
- <file name="qf_mem.c">
- <text>/*! @file
- * @brief ::QMPool implementatin (Memory Pool)
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- Q_DEFINE_THIS_MODULE("qf_mem")
- $define ${QF::QMPool}</text>
- </file>
- <!--${src::qf::qf_qact.c}-->
- <file name="qf_qact.c">
- <text>/*! @file
- * @brief QActive_ctor() definition
- *
- * @details
- * This file must remain separate from the rest to avoid pulling in the
- * "virtual" functions QHsm::QHsm_init_() and QHsm::QHsm_dispatch_() in
- * case they are not used by the application.
- *
- * @sa qf_qmact.c
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- Q_DEFINE_THIS_MODULE("qf_qact")
- //============================================================================
- $define ${QF::QActive::registry_[QF_MAX_ACTIVE + 1U]}
- $define ${QF::QF-base::intLock_}
- $define ${QF::QF-base::intNest_}
- $define ${QF::QF-pkg::readySet_}
- $define ${QF::QF-pkg::bzero}
- //============================================================================
- $define ${QF::QActive::ctor}
- $define ${QF::QActive::register_}
- $define ${QF::QActive::unregister_}
- //============================================================================
- $define ${QF-types::QF_LOG2}</text>
- </file>
- <!--${src::qf::qf_qmact.c}-->
- <file name="qf_qmact.c">
- <text>/*! @file
- * @brief QMActive_ctor() definition
- *
- * @details
- * This file must remain separate from the rest to avoid pulling in the
- * "virtual" functions QHsm::QHsm_init_() and QHsm::QHsm_dispatch_() in
- * case they are not used by the application.
- *
- * @sa qf_qact.c
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- /*Q_DEFINE_THIS_MODULE("qf_qmact")*/
- /*
- * This internal macro encapsulates the violation of MISRA-C 2012
- * Rule 11.3(req) "A cast shall not be performed between a pointer to
- * object type and a poiner to a different object type".
- */
- #define QMSM_CAST_(ptr_) ((QMsm *)(ptr_))
- $define ${QF::QMActive}</text>
- </file>
- <!--${src::qf::qf_qeq.c}-->
- <file name="qf_qeq.c">
- <text>/*! @file
- * @brief ::QEQueue implementation (QP native thread-safe queue)
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- Q_DEFINE_THIS_MODULE("qf_qeq")
- $define ${QF::QEQueue}</text>
- </file>
- <!--${src::qf::qf_ps.c}-->
- <file name="qf_ps.c">
- <text>/*! @file
- * @brief Publish-Subscribe services
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- Q_DEFINE_THIS_MODULE("qf_ps")
- /*==========================================================================*/
- $define ${QF::QActive::subscrList_}
- $define ${QF::QActive::maxPubSignal_}
- $define ${QF::QActive::psInit}
- $define ${QF::QActive::publish_}
- $define ${QF::QActive::subscribe}
- $define ${QF::QActive::unsubscribe}
- $define ${QF::QActive::unsubscribeAll}</text>
- </file>
- <!--${src::qf::qf_time.c}-->
- <file name="qf_time.c">
- <text>/*! @file
- * @brief QF/C time events and time management services
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- Q_DEFINE_THIS_MODULE("qf_time")
- #ifdef Q_SPY
- /*! intertnal macro to encapsulate a MISRA deviation
- * @details
- * This internal macro encapsulates the violation of MISRA-C 2012
- * Rule 11.5(A) "A conversion should not be performed from pointer to void
- * into pointer to object".
- */
- #define QACTIVE_CAST_(ptr_) ((QActive *)(ptr_))
- #endif
- $define ${QF::QTimeEvt}</text>
- </file>
- </directory>
- <!--${src::qv}-->
- <directory name="qv">
- <!--${src::qv::qv.c}-->
- <file name="qv.c">
- <text>/*! @file
- * @brief Cooperative QV kernel, implementation of kernel-specific functions.
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope internal interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- /* protection against including this source file in a wrong project */
- #ifndef QV_H_
- #error "Source file included in a project NOT based on the QV kernel"
- #endif /* QV_H_ */
- Q_DEFINE_THIS_MODULE("qv")
- /*==========================================================================*/
- $define ${QV::QV-base}
- $define ${QV::QF-cust}
- $define ${QV::QActive}</text>
- </file>
- </directory>
- <!--${src::qk}-->
- <directory name="qk">
- <!--${src::qk::qk.c}-->
- <file name="qk.c">
- <text>/*! @file
- * @brief QK preemptive kernel implementation
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope internal interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- /* protection against including this source file in a wrong project */
- #ifndef QK_H_
- #error "Source file included in a project NOT based on the QK kernel"
- #endif /* QK_H_ */
- Q_DEFINE_THIS_MODULE("qk")
- /*==========================================================================*/
- $define ${QK::QK-base}
- $define ${QK::QF-cust}
- $define ${QK::QActive}
- $define ${QK::QK-extern-C}</text>
- </file>
- </directory>
- <!--${src::qxk}-->
- <directory name="qxk">
- <!--${src::qxk::qxk.c}-->
- <file name="qxk.c">
- <text>/*! @file
- * @brief QXK preemptive dual-mode kernel core functions
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope internal interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- /* protection against including this source file in a wrong project */
- #ifndef QXK_H_
- #error "Source file included in a project NOT based on the QXK kernel"
- #endif /* QXK_H_ */
- Q_DEFINE_THIS_MODULE("qxk")
- /*==========================================================================*/
- $define ${QXK::QXK-base}
- $define ${QXK::QF-cust}
- $define ${QXK::QActive}
- $define ${QXK::QXK-extern-C}
- /*==========================================================================*/
- $define ${QXK-impl}</text>
- </file>
- <!--${src::qxk::qxk_mutex.c}-->
- <file name="qxk_mutex.c">
- <text>/*! @file
- * @brief ::QXMutex class definition.
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- /* protection against including this source file in a wrong project */
- #ifndef QXK_H_
- #error "Source file included in a project NOT based on the QXK kernel"
- #endif /* QXK_H_ */
- Q_DEFINE_THIS_MODULE("qxk_mutex")
- /*==========================================================================*/
- $define ${QXK::QXMutex}</text>
- </file>
- <!--${src::qxk::qxk_sema.c}-->
- <file name="qxk_sema.c">
- <text>/*! @file
- * @brief ::QXSemaphore class definition.
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope internal interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- /* protection against including this source file in a wrong project */
- #ifndef QXK_H_
- #error "Source file included in a project NOT based on the QXK kernel"
- #endif /* QXK_H_ */
- Q_DEFINE_THIS_MODULE("qxk_sema")
- /*==========================================================================*/
- $define ${QXK::QXSemaphore}</text>
- </file>
- <!--${src::qxk::qxk_xthr.c}-->
- <file name="qxk_xthr.c">
- <text>/*! @file
- * @brief ::QXThread class definition.
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope internal interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #ifdef Q_SPY /* QS software tracing enabled? */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- #else
- #include "qs_dummy.h" /* disable the QS software tracing */
- #endif /* Q_SPY */
- /* protection against including this source file in a wrong project */
- #ifndef QXK_H_
- #error "Source file included in a project NOT based on the QXK kernel"
- #endif /* QXK_H_ */
- Q_DEFINE_THIS_MODULE("qxk_xthr")
- /*==========================================================================*/
- $define ${QXK::QXThread}</text>
- </file>
- </directory>
- <!--${src::qs}-->
- <directory name="qs">
- <!--${src::qs::qs.c}-->
- <file name="qs.c">
- <text>/*! @file
- * @brief QS software tracing services
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS package-scope interface */
- #include "qstamp.h" /* QP time-stamp */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- Q_DEFINE_THIS_MODULE("qs")
- /* ensure that the predefined records don't overlap the
- * user records (application-specific).
- */
- Q_ASSERT_STATIC((enum_t)QS_PRE_MAX <= (enum_t)QS_USER);
- /*==========================================================================*/
- $define ${QS::QS-tx}</text>
- </file>
- <!--${src::qs::qs_64bit.c}-->
- <file name="qs_64bit.c">
- <text>/*! @file
- * @brief QS long-long (64-bit) output
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS package-scope internal interface */
- $define ${QS::QS-tx-64bit}</text>
- </file>
- <!--${src::qs::qs_fp.c}-->
- <file name="qs_fp.c">
- <text>/*! @file
- * @brief QS floating point output implementation
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS package-scope internal interface */
- $define ${QS::QS-tx-fp}</text>
- </file>
- <!--${src::qs::qs_rx.c}-->
- <file name="qs_rx.c">
- <text>/*! @file
- * @brief QS/C receive channel services
- */
- #define QP_IMPL /* this is QP implementation */
- #include "qs_port.h" /* QS port */
- #include "qs_pkg.h" /* QS package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- Q_DEFINE_THIS_MODULE("qs_rx")
- /*==========================================================================*/
- #if (QS_OBJ_PTR_SIZE == 1U)
- typedef uint8_t QSObj;
- #elif (QS_OBJ_PTR_SIZE == 2U)
- typedef uint16_t QSObj;
- #elif (QS_OBJ_PTR_SIZE == 4U)
- typedef uint32_t QSObj;
- #elif (QS_OBJ_PTR_SIZE == 8U)
- typedef uint64_t QSObj;
- #endif
- /*! @cond
- * Exclude the following internals from the Doxygen documentation
- * Extended-state variables used for parsing various QS-RX Records
- */
- typedef struct {
- uint32_t param1;
- uint32_t param2;
- uint32_t param3;
- uint8_t idx;
- uint8_t cmdId;
- } CmdVar;
- typedef struct {
- uint_fast8_t rate;
- } TickVar;
- typedef struct {
- uint16_t offs;
- uint8_t size;
- uint8_t num;
- uint8_t idx;
- } PeekVar;
- typedef struct {
- uint32_t data;
- uint16_t offs;
- uint8_t size;
- uint8_t num;
- uint8_t idx;
- uint8_t fill;
- } PokeVar;
- typedef struct {
- uint8_t data[16];
- uint8_t idx;
- int8_t recId; /* global/local */
- } FltVar;
- typedef struct {
- QSObj addr;
- uint8_t idx;
- uint8_t kind; /* see qs.h, enum QSpyObjKind */
- int8_t recId;
- } ObjVar;
- typedef struct {
- QEvt *e;
- uint8_t *p;
- QSignal sig;
- uint16_t len;
- uint8_t prio;
- uint8_t idx;
- } EvtVar;
- /* extended-state variables for the current state */
- static struct {
- union Variant {
- CmdVar cmd;
- TickVar tick;
- PeekVar peek;
- PokeVar poke;
- FltVar flt;
- ObjVar obj;
- EvtVar evt;
- #ifdef Q_UTEST
- struct QS_TProbe tp;
- #endif /* Q_UTEST */
- } var;
- uint8_t state;
- uint8_t esc;
- uint8_t seq;
- uint8_t chksum;
- } l_rx;
- enum {
- ERROR_STATE,
- WAIT4_SEQ,
- WAIT4_REC,
- WAIT4_INFO_FRAME,
- WAIT4_CMD_ID,
- WAIT4_CMD_PARAM1,
- WAIT4_CMD_PARAM2,
- WAIT4_CMD_PARAM3,
- WAIT4_CMD_FRAME,
- WAIT4_RESET_FRAME,
- WAIT4_TICK_RATE,
- WAIT4_TICK_FRAME,
- WAIT4_PEEK_OFFS,
- WAIT4_PEEK_SIZE,
- WAIT4_PEEK_NUM,
- WAIT4_PEEK_FRAME,
- WAIT4_POKE_OFFS,
- WAIT4_POKE_SIZE,
- WAIT4_POKE_NUM,
- WAIT4_POKE_DATA,
- WAIT4_POKE_FRAME,
- WAIT4_FILL_DATA,
- WAIT4_FILL_FRAME,
- WAIT4_FILTER_LEN,
- WAIT4_FILTER_DATA,
- WAIT4_FILTER_FRAME,
- WAIT4_OBJ_KIND,
- WAIT4_OBJ_ADDR,
- WAIT4_OBJ_FRAME,
- WAIT4_QUERY_KIND,
- WAIT4_QUERY_FRAME,
- WAIT4_EVT_PRIO,
- WAIT4_EVT_SIG,
- WAIT4_EVT_LEN,
- WAIT4_EVT_PAR,
- WAIT4_EVT_FRAME
- #ifdef Q_UTEST
- ,
- WAIT4_TEST_SETUP_FRAME,
- WAIT4_TEST_TEARDOWN_FRAME,
- WAIT4_TEST_PROBE_DATA,
- WAIT4_TEST_PROBE_ADDR,
- WAIT4_TEST_PROBE_FRAME,
- WAIT4_TEST_CONTINUE_FRAME
- #endif /* Q_UTEST */
- };
- /* static helper functions... */
- static void QS_rxParseData_(uint8_t const b);
- //static void QS_rxHandleGoodFrame_(uint8_t const state);
- static void QS_rxHandleBadFrame_(uint8_t const state);
- static void QS_rxReportAck_(int8_t const recId);
- static void QS_rxReportError_(int8_t const code);
- static void QS_rxReportDone_(int8_t const recId);
- static void QS_rxPoke_(void);
- /*! Internal QS-RX macro to encapsulate transition in the QS-RX FSM */
- #define QS_RX_TRAN_(target_) (l_rx.state = (uint8_t)(target_))
- /*! @endcond */
- /*==========================================================================*/
- $define ${QS::QS-rx}
- /*==========================================================================*/
- static void QS_rxParseData_(uint8_t const b) {
- switch (l_rx.state) {
- case (uint8_t)WAIT4_SEQ: {
- ++l_rx.seq;
- if (l_rx.seq != b) {
- QS_rxReportError_(0x42);
- l_rx.seq = b; /* update the sequence */
- }
- QS_RX_TRAN_(WAIT4_REC);
- break;
- }
- case (uint8_t)WAIT4_REC: {
- switch (b) {
- case (uint8_t)QS_RX_INFO:
- QS_RX_TRAN_(WAIT4_INFO_FRAME);
- break;
- case (uint8_t)QS_RX_COMMAND:
- QS_RX_TRAN_(WAIT4_CMD_ID);
- break;
- case (uint8_t)QS_RX_RESET:
- QS_RX_TRAN_(WAIT4_RESET_FRAME);
- break;
- case (uint8_t)QS_RX_TICK:
- QS_RX_TRAN_(WAIT4_TICK_RATE);
- break;
- case (uint8_t)QS_RX_PEEK:
- if (QS_rxPriv_.currObj[AP_OBJ] != (void *)0) {
- l_rx.var.peek.offs = 0U;
- l_rx.var.peek.idx = 0U;
- QS_RX_TRAN_(WAIT4_PEEK_OFFS);
- }
- else {
- QS_rxReportError_((int8_t)QS_RX_PEEK);
- QS_RX_TRAN_(ERROR_STATE);
- }
- break;
- case (uint8_t)QS_RX_POKE: /* intentionally fall-through */
- case (uint8_t)QS_RX_FILL:
- l_rx.var.poke.fill =
- ((b == (uint8_t)QS_RX_FILL) ? 1U : 0U);
- if (QS_rxPriv_.currObj[AP_OBJ] != (void *)0) {
- l_rx.var.poke.offs = 0U;
- l_rx.var.poke.idx = 0U;
- QS_RX_TRAN_(WAIT4_POKE_OFFS);
- }
- else {
- QS_rxReportError_((l_rx.var.poke.fill != 0U)
- ? (int8_t)QS_RX_FILL
- : (int8_t)QS_RX_POKE);
- QS_RX_TRAN_(ERROR_STATE);
- }
- break;
- case (uint8_t)QS_RX_GLB_FILTER: /* intentionally fall-through */
- case (uint8_t)QS_RX_LOC_FILTER:
- l_rx.var.flt.recId = (int8_t)b;
- QS_RX_TRAN_(WAIT4_FILTER_LEN);
- break;
- case (uint8_t)QS_RX_AO_FILTER: /* intentionally fall-through */
- case (uint8_t)QS_RX_CURR_OBJ:
- l_rx.var.obj.recId = (int8_t)b;
- QS_RX_TRAN_(WAIT4_OBJ_KIND);
- break;
- case (uint8_t)QS_RX_QUERY_CURR:
- l_rx.var.obj.recId = (int8_t)QS_RX_QUERY_CURR;
- QS_RX_TRAN_(WAIT4_QUERY_KIND);
- break;
- case (uint8_t)QS_RX_EVENT:
- QS_RX_TRAN_(WAIT4_EVT_PRIO);
- break;
- #ifdef Q_UTEST
- case (uint8_t)QS_RX_TEST_SETUP:
- QS_RX_TRAN_(WAIT4_TEST_SETUP_FRAME);
- break;
- case (uint8_t)QS_RX_TEST_TEARDOWN:
- QS_RX_TRAN_(WAIT4_TEST_TEARDOWN_FRAME);
- break;
- case (uint8_t)QS_RX_TEST_CONTINUE:
- QS_RX_TRAN_(WAIT4_TEST_CONTINUE_FRAME);
- break;
- case (uint8_t)QS_RX_TEST_PROBE:
- if (QS_testData.tpNum
- < (uint8_t)(sizeof(QS_testData.tpBuf)
- / sizeof(QS_testData.tpBuf[0])))
- {
- l_rx.var.tp.data = 0U;
- l_rx.var.tp.idx = 0U;
- QS_RX_TRAN_(WAIT4_TEST_PROBE_DATA);
- }
- else { /* the number of Test-Probes exceeded */
- QS_rxReportError_((int8_t)QS_RX_TEST_PROBE);
- QS_RX_TRAN_(ERROR_STATE);
- }
- break;
- #endif /* Q_UTEST */
- default:
- QS_rxReportError_(0x43);
- QS_RX_TRAN_(ERROR_STATE);
- break;
- }
- break;
- }
- case (uint8_t)WAIT4_INFO_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_CMD_ID: {
- l_rx.var.cmd.cmdId = b;
- l_rx.var.cmd.idx = 0U;
- l_rx.var.cmd.param1 = 0U;
- l_rx.var.cmd.param2 = 0U;
- l_rx.var.cmd.param3 = 0U;
- QS_RX_TRAN_(WAIT4_CMD_PARAM1);
- break;
- }
- case (uint8_t)WAIT4_CMD_PARAM1: {
- l_rx.var.cmd.param1 |= ((uint32_t)b << l_rx.var.cmd.idx);
- l_rx.var.cmd.idx += 8U;
- if (l_rx.var.cmd.idx == (8U * 4U)) {
- l_rx.var.cmd.idx = 0U;
- QS_RX_TRAN_(WAIT4_CMD_PARAM2);
- }
- break;
- }
- case (uint8_t)WAIT4_CMD_PARAM2: {
- l_rx.var.cmd.param2 |= ((uint32_t)b << l_rx.var.cmd.idx);
- l_rx.var.cmd.idx += 8U;
- if (l_rx.var.cmd.idx == (8U * 4U)) {
- l_rx.var.cmd.idx = 0U;
- QS_RX_TRAN_(WAIT4_CMD_PARAM3);
- }
- break;
- }
- case (uint8_t)WAIT4_CMD_PARAM3: {
- l_rx.var.cmd.param3 |= ((uint32_t)b << l_rx.var.cmd.idx);
- l_rx.var.cmd.idx += 8U;
- if (l_rx.var.cmd.idx == (8U * 4U)) {
- l_rx.var.cmd.idx = 0U;
- QS_RX_TRAN_(WAIT4_CMD_FRAME);
- }
- break;
- }
- case (uint8_t)WAIT4_CMD_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_RESET_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_TICK_RATE: {
- l_rx.var.tick.rate = (uint_fast8_t)b;
- QS_RX_TRAN_(WAIT4_TICK_FRAME);
- break;
- }
- case (uint8_t)WAIT4_TICK_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_PEEK_OFFS: {
- if (l_rx.var.peek.idx == 0U) {
- l_rx.var.peek.offs = (uint16_t)b;
- l_rx.var.peek.idx += 8U;
- }
- else {
- l_rx.var.peek.offs |= (uint16_t)((uint16_t)b << 8U);
- QS_RX_TRAN_(WAIT4_PEEK_SIZE);
- }
- break;
- }
- case (uint8_t)WAIT4_PEEK_SIZE: {
- if ((b == 1U) || (b == 2U) || (b == 4U)) {
- l_rx.var.peek.size = b;
- QS_RX_TRAN_(WAIT4_PEEK_NUM);
- }
- else {
- QS_rxReportError_((int8_t)QS_RX_PEEK);
- QS_RX_TRAN_(ERROR_STATE);
- }
- break;
- }
- case (uint8_t)WAIT4_PEEK_NUM: {
- l_rx.var.peek.num = b;
- QS_RX_TRAN_(WAIT4_PEEK_FRAME);
- break;
- }
- case (uint8_t)WAIT4_PEEK_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_POKE_OFFS: {
- if (l_rx.var.poke.idx == 0U) {
- l_rx.var.poke.offs = (uint16_t)b;
- l_rx.var.poke.idx = 1U;
- }
- else {
- l_rx.var.poke.offs |= (uint16_t)((uint16_t)b << 8U);
- QS_RX_TRAN_(WAIT4_POKE_SIZE);
- }
- break;
- }
- case (uint8_t)WAIT4_POKE_SIZE: {
- if ((b == 1U) || (b == 2U) || (b == 4U)) {
- l_rx.var.poke.size = b;
- QS_RX_TRAN_(WAIT4_POKE_NUM);
- }
- else {
- QS_rxReportError_((l_rx.var.poke.fill != 0U)
- ? (int8_t)QS_RX_FILL
- : (int8_t)QS_RX_POKE);
- QS_RX_TRAN_(ERROR_STATE);
- }
- break;
- }
- case (uint8_t)WAIT4_POKE_NUM: {
- if (b > 0U) {
- l_rx.var.poke.num = b;
- l_rx.var.poke.data = 0U;
- l_rx.var.poke.idx = 0U;
- QS_RX_TRAN_((l_rx.var.poke.fill != 0U)
- ? WAIT4_FILL_DATA
- : WAIT4_POKE_DATA);
- }
- else {
- QS_rxReportError_((l_rx.var.poke.fill != 0U)
- ? (int8_t)QS_RX_FILL
- : (int8_t)QS_RX_POKE);
- QS_RX_TRAN_(ERROR_STATE);
- }
- break;
- }
- case (uint8_t)WAIT4_FILL_DATA: {
- l_rx.var.poke.data |= ((uint32_t)b << l_rx.var.poke.idx);
- l_rx.var.poke.idx += 8U;
- if ((uint8_t)(l_rx.var.poke.idx >> 3U) == l_rx.var.poke.size) {
- QS_RX_TRAN_(WAIT4_FILL_FRAME);
- }
- break;
- }
- case (uint8_t)WAIT4_POKE_DATA: {
- l_rx.var.poke.data |= ((uint32_t)b << l_rx.var.poke.idx);
- l_rx.var.poke.idx += 8U;
- if ((uint8_t)(l_rx.var.poke.idx >> 3U) == l_rx.var.poke.size) {
- QS_rxPoke_();
- --l_rx.var.poke.num;
- if (l_rx.var.poke.num == 0U) {
- QS_RX_TRAN_(WAIT4_POKE_FRAME);
- }
- }
- break;
- }
- case (uint8_t)WAIT4_FILL_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case WAIT4_POKE_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_FILTER_LEN: {
- if (b == sizeof(l_rx.var.flt.data)) {
- l_rx.var.flt.idx = 0U;
- QS_RX_TRAN_(WAIT4_FILTER_DATA);
- }
- else {
- QS_rxReportError_(l_rx.var.flt.recId);
- QS_RX_TRAN_(ERROR_STATE);
- }
- break;
- }
- case (uint8_t)WAIT4_FILTER_DATA: {
- l_rx.var.flt.data[l_rx.var.flt.idx] = b;
- ++l_rx.var.flt.idx;
- if (l_rx.var.flt.idx == sizeof(l_rx.var.flt.data)) {
- QS_RX_TRAN_(WAIT4_FILTER_FRAME);
- }
- break;
- }
- case (uint8_t)WAIT4_FILTER_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_OBJ_KIND: {
- if (b <= (uint8_t)SM_AO_OBJ) {
- l_rx.var.obj.kind = b;
- l_rx.var.obj.addr = 0U;
- l_rx.var.obj.idx = 0U;
- QS_RX_TRAN_(WAIT4_OBJ_ADDR);
- }
- else {
- QS_rxReportError_(l_rx.var.obj.recId);
- QS_RX_TRAN_(ERROR_STATE);
- }
- break;
- }
- case (uint8_t)WAIT4_OBJ_ADDR: {
- l_rx.var.obj.addr |= ((QSObj)b << l_rx.var.obj.idx);
- l_rx.var.obj.idx += 8U;
- if (l_rx.var.obj.idx == (uint8_t)(8U * QS_OBJ_PTR_SIZE)) {
- QS_RX_TRAN_(WAIT4_OBJ_FRAME);
- }
- break;
- }
- case (uint8_t)WAIT4_OBJ_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_QUERY_KIND: {
- if (b < (uint8_t)MAX_OBJ) {
- l_rx.var.obj.kind = b;
- QS_RX_TRAN_(WAIT4_QUERY_FRAME);
- }
- else {
- QS_rxReportError_(l_rx.var.obj.recId);
- QS_RX_TRAN_(ERROR_STATE);
- }
- break;
- }
- case (uint8_t)WAIT4_QUERY_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_EVT_PRIO: {
- l_rx.var.evt.prio = b;
- l_rx.var.evt.sig = 0U;
- l_rx.var.evt.idx = 0U;
- QS_RX_TRAN_(WAIT4_EVT_SIG);
- break;
- }
- case (uint8_t)WAIT4_EVT_SIG: {
- l_rx.var.evt.sig |= (QSignal)((uint32_t)b << l_rx.var.evt.idx);
- l_rx.var.evt.idx += 8U;
- if (l_rx.var.evt.idx == (uint8_t)(8U * Q_SIGNAL_SIZE)) {
- l_rx.var.evt.len = 0U;
- l_rx.var.evt.idx = 0U;
- QS_RX_TRAN_(WAIT4_EVT_LEN);
- }
- break;
- }
- case (uint8_t)WAIT4_EVT_LEN: {
- l_rx.var.evt.len |= (uint16_t)((uint32_t)b << l_rx.var.evt.idx);
- l_rx.var.evt.idx += 8U;
- if (l_rx.var.evt.idx == (8U * 2U)) {
- if ((l_rx.var.evt.len + sizeof(QEvt)) <=
- QF_poolGetMaxBlockSize())
- {
- /* report Ack before generating any other QS records */
- QS_rxReportAck_((int8_t)QS_RX_EVENT);
- l_rx.var.evt.e = QF_newX_(
- ((uint_fast16_t)l_rx.var.evt.len + sizeof(QEvt)),
- 0U, /* margin */
- (enum_t)l_rx.var.evt.sig);
- if (l_rx.var.evt.e != (QEvt *)0) { /* evt allocated? */
- l_rx.var.evt.p = (uint8_t *)l_rx.var.evt.e;
- l_rx.var.evt.p = &l_rx.var.evt.p[sizeof(QEvt)];
- if (l_rx.var.evt.len > 0U) {
- QS_RX_TRAN_(WAIT4_EVT_PAR);
- }
- else {
- QS_RX_TRAN_(WAIT4_EVT_FRAME);
- }
- }
- else {
- QS_rxReportError_((int8_t)QS_RX_EVENT);
- QS_RX_TRAN_(ERROR_STATE);
- }
- }
- else {
- QS_rxReportError_((int8_t)QS_RX_EVENT);
- QS_RX_TRAN_(ERROR_STATE);
- }
- }
- break;
- }
- case (uint8_t)WAIT4_EVT_PAR: { /* event parameters */
- *l_rx.var.evt.p = b;
- ++l_rx.var.evt.p;
- --l_rx.var.evt.len;
- if (l_rx.var.evt.len == 0U) {
- QS_RX_TRAN_(WAIT4_EVT_FRAME);
- }
- break;
- }
- case (uint8_t)WAIT4_EVT_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- #ifdef Q_UTEST
- case (uint8_t)WAIT4_TEST_SETUP_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_TEST_TEARDOWN_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_TEST_CONTINUE_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- case (uint8_t)WAIT4_TEST_PROBE_DATA: {
- l_rx.var.tp.data |= ((uint32_t)b << l_rx.var.tp.idx);
- l_rx.var.tp.idx += 8U;
- if (l_rx.var.tp.idx == (uint8_t)(8U * sizeof(uint32_t))) {
- l_rx.var.tp.addr = 0U;
- l_rx.var.tp.idx = 0U;
- QS_RX_TRAN_(WAIT4_TEST_PROBE_ADDR);
- }
- break;
- }
- case (uint8_t)WAIT4_TEST_PROBE_ADDR: {
- l_rx.var.tp.addr |= ((QSFun)b << l_rx.var.tp.idx);
- l_rx.var.tp.idx += 8U;
- if (l_rx.var.tp.idx == (uint8_t)(8U * QS_FUN_PTR_SIZE)) {
- QS_RX_TRAN_(WAIT4_TEST_PROBE_FRAME);
- }
- break;
- }
- case (uint8_t)WAIT4_TEST_PROBE_FRAME: {
- /* keep ignoring the data until a frame is collected */
- break;
- }
- #endif /* Q_UTEST */
- case (uint8_t)ERROR_STATE: {
- /* keep ignoring the data until a good frame is collected */
- break;
- }
- default: { /* unexpected or unimplemented state */
- QS_rxReportError_(0x45);
- QS_RX_TRAN_(ERROR_STATE);
- break;
- }
- }
- }
- /*..........................................................................*/
- static void QS_rxHandleBadFrame_(uint8_t const state) {
- QS_rxReportError_(0x50); /* report error for all bad frames */
- switch (state) {
- case WAIT4_EVT_FRAME: {
- Q_ASSERT_ID(910, l_rx.var.evt.e != (QEvt *)0);
- #if (QF_MAX_EPOOL > 0U)
- QF_gc(l_rx.var.evt.e); /* don't leak an allocated event */
- #endif
- break;
- }
- default: {
- /* intentionally empty */
- break;
- }
- }
- }
- /*..........................................................................*/
- static void QS_rxReportAck_(int8_t const recId) {
- QS_CRIT_STAT_
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_RX_STATUS);
- QS_U8_PRE_(recId); /* record ID */
- QS_endRec_();
- QS_CRIT_X_();
- QS_REC_DONE(); /* user callback (if defined) */
- }
- /*..........................................................................*/
- static void QS_rxReportError_(int8_t const code) {
- QS_CRIT_STAT_
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_RX_STATUS);
- QS_U8_PRE_(0x80U | (uint8_t)code); /* error code */
- QS_endRec_();
- QS_CRIT_X_();
- QS_REC_DONE(); /* user callback (if defined) */
- }
- /*..........................................................................*/
- static void QS_rxReportDone_(int8_t const recId) {
- QS_CRIT_STAT_
- QS_CRIT_E_();
- QS_beginRec_((uint_fast8_t)QS_TARGET_DONE);
- QS_TIME_PRE_(); /* timestamp */
- QS_U8_PRE_(recId); /* record ID */
- QS_endRec_();
- QS_CRIT_X_();
- QS_REC_DONE(); /* user callback (if defined) */
- }
- /*..........................................................................*/
- static void QS_rxPoke_(void) {
- uint8_t *ptr = (uint8_t *)QS_rxPriv_.currObj[AP_OBJ];
- ptr = &ptr[l_rx.var.poke.offs];
- switch (l_rx.var.poke.size) {
- case 1:
- *ptr = (uint8_t)l_rx.var.poke.data;
- break;
- case 2:
- *(uint16_t *)ptr = (uint16_t)l_rx.var.poke.data;
- break;
- case 4:
- *(uint32_t *)ptr = l_rx.var.poke.data;
- break;
- default:
- Q_ERROR_ID(900);
- break;
- }
- l_rx.var.poke.data = 0U;
- l_rx.var.poke.idx = 0U;
- l_rx.var.poke.offs += (uint16_t)l_rx.var.poke.size;
- }</text>
- </file>
- <!--${src::qs::qutest.c}-->
- <file name="qutest.c">
- <text>/*! @file
- * @brief QUTest unit testing harness
- */
- /* Include this content in the build only when Q_UTEST is defined */
- #ifdef Q_UTEST
- #define QP_IMPL /* this is QP implementation */
- #include "qf_port.h" /* QF port */
- #include "qf_pkg.h" /* QF package-scope interface */
- #include "qassert.h" /* QP embedded systems-friendly assertions */
- #include "qs_port.h" /* include QS port */
- #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
- /*==========================================================================*/
- /* QUTest unit testing harness */
- $define ${QUTest}
- /*..........................................................................*/
- Q_NORETURN Q_onAssert(
- char const * module,
- int_t location)
- {
- QS_BEGIN_NOCRIT_PRE_(QS_ASSERT_FAIL, 0U)
- QS_TIME_PRE_();
- QS_U16_PRE_(location);
- QS_STR_PRE_((module != (char *)0) ? module : "?");
- QS_END_NOCRIT_PRE_()
- QS_onFlush(); /* flush the assertion record to the host */
- QS_onCleanup(); /* cleanup after the failure */
- QS_onReset(); /* reset the target to prevent the code from continuing */
- for (;;) { /* QS_onReset() should not return, but to ensure no-return */
- }
- }
- /*..........................................................................*/
- QSTimeCtr QS_onGetTime(void) {
- return (++QS_testData.testTime);
- }
- /*==========================================================================*/
- /* QP-stub for QUTest
- * NOTE: The QP-stub is needed for unit testing QP applications, but might
- * NOT be needed for testing QP itself. In that case, the build process
- * can define Q_UTEST=0 to exclude the QP-stub from the build.
- */
- #if Q_UTEST != 0
- Q_DEFINE_THIS_MODULE("qutest")
- $define ${QUTest-stub}
- #endif /* Q_UTEST != 0 */
- #endif /* Q_UTEST */</text>
- </file>
- <!--${src::qs::qstamp.c}-->
- <file name="qstamp.c">
- <text>/*! @file
- * @brief Application build time-stamp
- * @details
- * This module needs to be re-compiled in every new software build. To achive
- * this, it is recommended to delete the object file (qstamp.o, or qstamp.obj)
- * in the build directory before each build. (Most development tools allow
- * you to specify a pre-build command, which is the ideal place to delete
- * the qstamp object file.)
- */
- #include "qstamp.h"
- /*! the calendar date of the last translation of the form: "Mmm dd yyyy" */
- char const Q_BUILD_DATE[12] = __DATE__;
- /*! the time of the last translation of the form: "hh:mm:ss" */
- char const Q_BUILD_TIME[9] = __TIME__;</text>
- </file>
- </directory>
- </directory>
- </model>
|