From f8b93eb6a3e648d4053c8d85f7f36f91d93cd9f3 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 7 Apr 2025 14:54:15 +0100 Subject: [PATCH 001/251] First commit, framebuffer and mib_props_supp. Also including Makefiles, config.mk, and mib_props files --- Makefile | 21 ++ bin/main.out | Bin 0 -> 112520 bytes config.mk | 20 ++ include/framebuffer.h | 26 +++ include/mib_header_DAC.h | 35 ++++ include/mib_header_MQ1.h | 90 +++++++++ include/mib_macros.h | 47 +++++ include/mib_props_supp.h | 18 ++ include/mib_utils.h | 27 +++ include/mq1_quad.h | 12 ++ include/mq1_single.h | 12 ++ include/read_mq1_headers.h | 83 ++++++++ src/framebuffer.c | 40 ++++ src/main.c | 221 +++++++++++++++++++++ src/mib_props_supp.c | 95 +++++++++ src/mib_utils.c | 123 ++++++++++++ src/mq1_quad.c | 247 +++++++++++++++++++++++ src/mq1_single.c | 120 +++++++++++ src/read_mq1_headers.c | 395 +++++++++++++++++++++++++++++++++++++ 19 files changed, 1632 insertions(+) create mode 100644 Makefile create mode 100755 bin/main.out create mode 100644 config.mk create mode 100644 include/framebuffer.h create mode 100644 include/mib_header_DAC.h create mode 100644 include/mib_header_MQ1.h create mode 100644 include/mib_macros.h create mode 100644 include/mib_props_supp.h create mode 100644 include/mib_utils.h create mode 100644 include/mq1_quad.h create mode 100644 include/mq1_single.h create mode 100644 include/read_mq1_headers.h create mode 100644 src/framebuffer.c create mode 100644 src/main.c create mode 100644 src/mib_props_supp.c create mode 100644 src/mib_utils.c create mode 100644 src/mq1_quad.c create mode 100644 src/mq1_single.c create mode 100644 src/read_mq1_headers.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7749412 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +include config.mk + +.PHONY: all clean + +all: $(TARGET) + +$(TARGET): $(OBJECTS) | $(BINDIR) + $(CC) $(OBJECTS) -o $@ $(LDFLAGS) + +$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(OBJDIR): + mkdir -p $(OBJDIR) + +$(BINDIR): + mkdir -p $(BINDIR) + +clean: + rm -rf $(OBJDIR)/*.o $(TARGET) + diff --git a/bin/main.out b/bin/main.out new file mode 100755 index 0000000000000000000000000000000000000000..b9751d80d27177c00dd388a9ef68ee7231653441 GIT binary patch literal 112520 zcmeFa3wTu3)job^CPOZSBwU1usH1`niWsiOTb%#{g9eQPHbpQAxsYf`VlEh{NHoST zV;l`uY-+)#t+r|FC9TFUP=O$7qO~<%YSVtUO|7*P!LR8jwW*iR?|s+a=gdh+X#W4_ z`Ca;ydC1v&y?d>-*WP>W>$$MQm$BUGa2V##X?)Qj)iT{Hkh&U1_mdGGuaRcN8eZcZ z<7{IbxT5f9@_BX43}s}g!Ct}7*G z80YHnY=o&geg#7EoTlk?go|{15<)Njmg8><{_MZ;n(!c;XG=H*@n!g1g1^f&{skSL zhwv=?P1AIW4$s#igA4IDU(?fdc##e-MVO4gculjc3w3-k!ddw9;ctS*PDPlAzd87u zjlawBcQO7>^c$^hS*Ksrf|l#r6eZ|*tPP`&(r@DMcM1O3PSN<|kNs^j{>~tQ-PDbzZEtCzm796);r5ho1ZpjCC`ugc3j+) zI~=k8+BT*!Pu3^P#)K8pS`N8#sqJd*$Xd=&hmQS7{7lze|WO1>*c z(evmidN{U@Wanw4=y@J`CSn$Cc|He{hQT?CzYjI;8HTTgo#gi%&LNw{Ux+yIoMHSm z$Ttai_n{oJTfe(B-gY?0!WbE+^?MKJkhJs%5U2h=t;e);y0+6hEZI4%w}I|BN{GbPm&hP~$C!a}bO0r)c|g4(AZI^la6*F-*^88t)s1 z$C&mE!wszeit-B=amBYFHPy(@-n6-_G`q4Yx1uUL+wd>StSqR?&MT@ey%|JaQ9<6# z*;@)KDvQfXK`*!XvX^G8&R&+jCVjPU zP4?33eCca^*(;Z2Z$esGc>$FTWl3MU)VF%I$+9f3q^yz|te4=Z4gi%XK0rCq9OJI(b%kq`rADYFQ?5oq)ti0Zry>{i*YebiYEYG+m-Gn5! zd5g{L3QMXhi>OvrQ*K3eL1|uDesL)awkEftB6n-HGI_qqRajh7lD#Fjq?+a|+l1<^ zEYHm&u_D5`jQR>{stQW0$Q4P*R8cB3i)z_v8opYTN)2fp+4;qrDzP^7$@jY8B?o?I)LTmmPoE>&1% zLBY+&=7P2LO5f-ky}+(Y!sGP!0`)_J&n{IXmf6HsZm*~ zlfYeIWEbS;R^@_iV`Zh{0#urBtjJioWNG&Nx$_oU(Tl9u{JGpSIkCcb;HpA1?h=}) ziAVS%G0K?|3{~7jBb4Hb(i|qInQo^spy21g3BZ#WbIg6hgF7D@$6ZN4#zpMKii@#b zav2Y5x_WvswlGfP5zzb%9L$jrLO6?v{042fxi4X=IbL&*WbT(lN{?&AmkXdS9vja6 zg!%K@aPCpfUycpuzQg?0+HiA!!L$||Ztf$AciQl!1oW@ZhTHc=#^D^{p#5Hnsf*`u zjzoyt_m*B8&V7;j%Q>7QQS$pFrY^OIb0k81iNw^U<#3Kfh;uJx{*pU$B+9*+!vqm} zY&e?T`lZ-#mxbaSz=m_LYW~t}IP*4tUK>8n1QGgeIBhb2nKs;pbX zJY!&5kqtNZ|HR8}xVi5qUSq?}y*cq(8_u%<^VeX*&A!64CL3;FXEob!?&Hm0iw(D* znY7w)o{^ZpHXCl=`*+yzX(ltmP8*KZj`i!d;XL;+e?2zbJWpX-uMIcPeu($k@EHX3 zFJ!}cc3}PnY`A%r!L&geZk}z3%%L0!=p!D9sY{FvKg)(E+3>S%c(M&Y$A)`sIL}AS zUy2Q%Wr7G(ZTPu1Jk5rG!G?Qnc!~}8+wj>oJky5r{LB1h*>L;$SB?$m9@hL7*>Lmx zhiTvDlI|4xVbU(rZ9+dlnnPfJi_rIw=Fr#QB=nu6Ipp=%3cZaq z-MGJ8=nB#t;`(!hzKL`!=}e(FlIBp??-hC-X%2DysX|{znnPQ^N9Zd_b4cq?5_$<~ z4rTp@(3g z2pvb7Lsfs1&`#1EqWWuv{^Wb0IW+Z`3;jQ&IVAPx2>k(R4n_T$LcdFzLr}k0=wFlO z(9@qP^c$o(Brr!{HA88IP{R5w~{68k`A>AkR4@h$;>F*Kx z+oaDX-6{0Lq&al-w+a0KX$~3vEkfTznnOi@lhAjPK9_W@(A!9JXy`8&x`H%^g#H|% zZz4ULbf(Z7NplG3_X@p^G`oI(s?gVwW|!~x2z@1KcJ=-wp_h9hf8bqz-FpL>YgTr3 z8cklq-*u?zeg<9b1?Xp|ocEZ=IMzh|!-aDb&%6s7Fim!Jqa*t-=e25b2O)OZ*n@_yhYxD7Qb*&g$|9cJ(r-+t0wLJ_qB@ zN>q?PaA+Uv>;MOngC0~zXd}F@e>^(Azp-94G=j@F07?`I74mm%E~v`oPGTPf!BEdm zk6io=y6QP3NJ3YARwSAei55ko<&kKO8Esq}@(0^RXQOW*U8-xZ%Bd@qDh2ZO`Rlg# z8CzMD+rO)d!WFP8N*0UqH8@hgcO2~Ns!uajch$>y1QKWp0v6pL+(pzM6h438rGrF6 z4}Ho)`FfF4ugYnP&WZPGR8CFI=>q2THb&FXS7}_MI|E+i4|Ijrd?Fe!vTyG(wqA;q zHzeiIKF$V8Lk~3^5jkW9p&b-zL;(?B0KES;XoiWj7I=?{G4UZJ)^~1Q0kvPzYPm>P zYGZan?So2f54oFJnnsny3|kgG!23_7@ox)X8iM@*xd%kwga33S^D$H_*W^m`)bYjl45KHW9tEq)ns&#@m0k*OEd0K zj4fbnIe?lH#$ND*zM~jF`?g20D#h3g#^wVYy{Yjj@^saE(0rUgLuE=PhRTDx2wN?B zj7b4s6W9mfQ+Kj-m>Q*0f1^^9RVpW- zA29WOX&?7Nm71bbIbA)&)NYmfEtQ(4QoRWFG4%&3wN9n_Rca=JPNbsvofs6d6qQt5b=Wnqw z>RVN68-f_74zg_;-LI?E4wc%8Usog5I2f-OgMR}T_u~(se2vQW<0yL!1 z0R)#Rv>E82LJhR;HPpXN>0hn%$FM7-oe<iDFfexc1`!zjeliCu3$P>SLDKCKRKDGBAwz8@Gr2 zjjMVw(ux9hR4hru)!nNChgJp#>ADZnuDTbJ;FGl&25OD1SD*?LzU86kQtH5FU0k(U>)4-f{H!yI2$9Bd3cs!;_x}TI&xu{dK-Uhj3i#Ye>9v0_#CssVnsG z-y{wP>I&Vb;&7X;(48s{XXy%UQE@a%SLh}cM^ki#Zd7qJVOQun74KpEZdE(ojBiu% zUdI1%O!Deu{KvpwKCEZf9Q6Ib{^z8Vwzo;Jt5t$v3xm4-4AlJE|4md9=2xz1)QH@~ zmUbfl{yH_kiUyfcQSqfeX>Ajfwr*J3ZOs{e@aWlav)0Y6n6fmJy6;xHrM<7T<#W4gZ}Eu==J^M-GitUI zEpj&mnGL#hH=DStz6Zfhs{5XZxogF!dQJyO?L)AesR5O`QKg1d>Hvc8G4*DZx=f`G zs#F70&ySh9N~NBwQe!y1VX#23pQ#tB)EJeTtWrG)x|uprrGBuR6HWtJDgWTBK4r*MH2^ zuc*{DDz!$X)*|?vsT)-4VwKvUQkxJsA4KXEDm7W9HmlSY1aV9~OQnAD4JmJ{N^L_h zm8mY3`i@HNP^p~=&SL5x|3_-$fJ*IFsXYkJV``U5ZBePcDzy*6BBp*{rQWGhLn?Iu z!KF-XRH^wYbx@@m=v>R0x>=`Pm71bblU1q*!Szg?r&8loYKlrt zMX-*klU3@`hov^sRH_$2E>r*d7b)-0RjOa5W+EtH>MvDln@Y`6sW}LWnYve{KA=*I zRBAbb3Z{NTrB_e4- zWOkMfL2yDbz#M<)&M<`H9!-MR%?J3)Iy6| z1H^sZ!z!cHfzR!geyu7aHgMJ&K<37wYk=dExdv!aYk-i0rsrXWf@LJ+F7|~I@BDA& z3azZW4IgS-5ub<#s`DL#$gxZ7IW;HVxtnWb8MC`W8^xK_eDV+~1-P{PJ&5ahz3!;T zAHZ5DP>pGLd&sC-W6i-|1iNiD;|tLo%*XYeHD`>H1d|e&k8LT_SJ83A(e(1+jNqD? zF*tqbOAl8Ja!HYX-D>RDb6jk={eD^cG785hM-W5^-SBx{^Jk)oE31}QI=$v zhy=OTetln(>5fc)6&2LwJ4%To(;Iz9>pI8#n-ia1D6^`Vun<`1%euLrrLeNdLXq-T50gV8JQN7i)>}=VinNLz$Yzr(OQQYMhSNE3e$uD&W#2pvgen z#8-E9DAWTq1!$*2yA_%WG!1BvLVFeJ1?mUdr_hi>Gl6CS9Z=|?LUVu?0p)=d42zM5 zSy~RX1}KlMfF=uCSBnDr17B@m&{*$LU=yf=<+z06kFYA?;`P$5fy@|%ANyb!o}}=1 zhU3W!e_=T8@i&g9I4#L=eK174A zohb$6F~r+!%G=J7qA9=h#+VGjD{tG!B5KF16US7g?DEnlSsx^VSIHMfRZyXEM)atx7=IwnA6SQ|KM7>AKX4_w)jD)5 zKb$Em1+)ir3g}eOX`s=S)}br;y`cS|y`cS|GeKv8M)z5V?&Hq^T?9G@bP?!s&^4gZ zW!9m~G}O|L#%AdxfqR4sJgmA*E&GZ;a3_OMw-50^~?0<4!Fxk6#R zU<04K<^c~h9NIS>q?(tn;&8OHAKT6;rk=@mJ;8#38`9TpSQ*?nsCIaDFVtctXvR#? z--bl#D_HG=}l@h0>1YmbgI9u(~DAmz}0TyKpW=7X{CiUD zz-O2GdT)ER|5I2z+$2XQt-9-vQdgr`wRmK!uAx=G#N?%qVvbyhMS)lad*YGP;0X;I zgkgg;?B)KABNzr3p=BSucOuJn-#=n~wWE^zFBi*Xb$w(3Rza3!^{hewC$vs2oM7FH z{Vxdn(3aFbmT^Ms{&C-k)=i^z-^9GqTZB__u`S+2RrB@ z6@NfI(T}R);aYI3uFw@UPA}^gs5rWCSLko=Vgg+IoD}&Hvm4Q0Wog-j z#&be$NcTPm>d_r(CH~mUpy+Dm8Nf2DZhNQl-*{c(*(ie=YX)iDEVx(y6Vf3fDwx@- zW@OZ9O}-bvO1(VmzY*+Rz7T7pe~E}5W$uCJF?Tz95bdK8z7CY36G}Sh_T2h(`C2KX z`t2gC-_rM0zx|#{MZf)%!W>oO*>9^Z?|&NrbhU99dKMkS*DA}x<9b&T*ALCAqqR09 z^*=I1?oeM$fCF2bIp{sx8QUYqj-n1bG%QEn@H_C2eYdp`bM}?PbS4kid8jWb*33o* z&SyK3vjw?SA;y;Tp?94+YvkO63bNJ0p}sU(qS?!XF*en2WuHEKgJS@t9-OA zx=`Z152*#6420u<50~!pb)pIkwGB%DQu_7jYtz?oN0Nde1rs4OR<}TNi{G6O&x9>> z;}(CgIY-D1oE^yv*GE7=3|2F;T;9V)5iA#QFOW0AUqvM1=-Jg5sIfaB#636Av_K52@>R848_yZ zC&*)Rdqa3y-x1`APR-+Y_X5Ddq1+z<3mW?^LH4wnEWw5zL4vIo(#9n%Hm~};22xGk zg6wLxcsgDXWPg)JQ1nh9D0+j1G(RWEo>~iO>ky>9#zH!t5oCY4h19kQqV6oIqCYN3 zFvsF)X%*zLEDLGnO9vT&Co(nSceemQ(fuY6Y~C%%9 z4|S`T3-VaVLRw1%d7@7ves>W76us93g3bAY?CG(Ph8#hH-4@ceUXb=q3u(#{WLJlU zbgU6%f15^7^h_WqdaH#rX9%*V#X{Qrg0weVNXIfk_BUBbtyhrx1`BDpOpsu$g|wsz z@>q?9v@R6niE@qj-KhXj^db`oHqQ}cPmYB&qzDqsvXHi!g0yE^NRvkpbtWSnr(=d7 z`@Nb6MNbBTqNiC%^Ath$q*_Q@k|6CV7Sa(f$bOH7)W!%>pKKuwQGx`METqK{g!xaVwh70AwG`nT)O!KK{+WAo;GfX%?C>aY2xYyBfOlk zsG`3o$bNPB;^Q#a2Lwfz(;4t&1e@OxWRE(wA=1XJ9EQ0LIffz9@s=R_+bpD(vvvmV z?pjF0tAYg8Q4ytDx&?Wx+2U#C+7?A`(um*P2>?ZJFo9q*kEv1gS_^6D5F}V*A#KkH z(q3*MO>KhgDzcD{#|7D+qY)IH3pEry%R-tT6=YAQg|xK@((bpAj@^Rn_gY9T_gg4> znuRnxC`d5XLRy*xc`U_3TJII)36Dnn?gjuTda?-wo9_~2Pm+Z+)Cv-ev5@lH(By_i zX4as+<+g^jcTE-MG~WDBBTi;HiYvE7q@}Y;G6H*e<3y#F7om;ic8a9d=20q>qA)~N7<)CTr=hBm#bH< zX>v`KYl>Vwa!r1$hA$bt#WOVYqMONX)lmu4!^j zm1~MzJ#tN!Ym!`J5Ph(XLcBCKjnK<)a3?!c zx|ryh7CM1wqc7`)-~YX|^WZ$iw+I|6g%0r*)9eo6}Vf$ zXIk(~fnQbdJPV#6aF2r1E%@V~v+!>zc(n!pPT*bz=U8yJ!0#xy!h(M!aG!$fE%;%9 z-&1gt1=k52Qt&q{xJ2Ni3jV$YuN8Pe!OvLm7X?11;DZ+Y1%U?@{F((P0Y3OUkfFN~ zgFk)-j-mee;m=qRT;QWgBL4Wcz}yJ{j`-t2fw^S>9P!6ifw{K;9P!7U0&^1rIO31n z1m zJsRMMKmJN!Zsq_-{PB5#x#{oEaAJYWRP;kT_&k{IO!4ZFq6L^h+BmVf&PiaY(f+PO;j=<{`9P!5&1hyo zBmTHZ;2s4>{P7Hd-%@bIAEO2CRdB=~2fE>pAJQKS!2o}J2OLBF@n>McGagDZ;*ZY? z{GNg%{`gISLkf=gV}rm)6&&%$TLd0ZaKsk76AHOXy55NIO{IOAB zo|FTQ_+yp8JW>Z7@y87U^XwgP#2=Rn%tLy>5r4c;V4mg!j`(A;z&!Q`9Pvkoz`Q>I zIO2~Vyu>=;jRe3Ee|%G5-f;jN@yF)`=6wmk5r2G4V6TEB{&=6j%M={($6E#VD>&kh zIe_7X8Nlg<$E=Bbg-Wm?wBe7Gj>@@eD-q zv~d+S^d1eDYdGM^w0O)DJimpQCwN{9F;DP#exfv+CwQqEu}<((Ou#z9;}HvmaCq4v zg|OeF;i?xWSxFX;d4d;XA?67lk7RVwx!}f;)*uc!6k?v>4OobIf)}z7^8~NYLTZ~u zkNqCagM!%a(QuoQ5wPE*xmOU|J(>mpIKJx8igAzTEoWqj8!%&abDT!Vu=5%r2iVj(&NnRV!%kv6$7!>$UkS!@ zoaZg_Eu=_3SF9%0H$9crk{+i|(evb3B#qosZ z7=Dh^ZE-Yej^XDxzp*%qHOKICod2;nRw$18S~TOZbDZdJnpJVOX5s)g>>Ou?#q{|B zb=bpkZ`e7`Jd3FpOb3^P3|$SK{>VAbDzZS*2(^R7I>*Ve;70`JNQ|1Uu;Bj?m_s(; zyDYd|;N1#-$b!EtaEpRlEqIB*k1BYd1)nc4rxoaa)qEbjUlW)m20XsSEPRK+&nfs+3;veCoeG|1!S@LKf`S)XaHYWA3SMEs>ji#Q z!C$supTPPYr`Uq$3jCJh{)z=p6S!Bw4Hj$&{EmVjw&4EfSSNi7e!_y^5coX>cUbUG z1P&?qumwLV@KFW7Zoxr;^*PQv7Q98^V~YDv7Mv~cpo0Hq!G6H-!q0$nT^Ri>vmq{2 z3H)3(6V9>{rivmDaKM*YaQG)I=}ZN$vEUG3y)MK$aL|m_9Ze#MVF!QS6n>|Gx4aY) z!21%YPEDuU6I1!5+cBD^m}BgTxI5Mr`eh_B$)1S(x@g!S3*%tROj+ZR>Ud3uW{EUaWws&KN%cu76v|zM)crT9K z0^h)JAs;+-CvVvDAveBM3tRG0rzs?axlBUJw~sq z0dwLQnIEV%*h`Fa#>(HI_!p0rze(}0i11_ah(|;N9I*QEs?gvVyYn18GS2Qig9>fk zdDnlA(4E6k!aTO_d~L+G6Lsgh=c7&ME>zQ1X#%<*8Z7%MXeitS@%o&x5Eu`+X1 z`RZ7iXMp*Uu`+wW{Qa>q&jj-`V`b)e^^>tO&jItHu`+XT>mDofLNNbqtjrt z%m5gXqp{%JKWC6*WxEGKXwTDX z+^iGSvEu@~U&aK!b=>Gq+~6?|_(ijRK4il);jrv%`!_?E#f*3D`27j2gbwgaUR+@P z;m4v`y{uFfhcrYx9Y=6l15Uoh)VQk0ACxyJ_wln9`n|%hz@nGx&kW-O7&`R;KdeEO zO-iNuOcB<3cq`;3q$nL^xKJ^m0{99?r`vxy72kTEjU`@Ko;MLkPnR(l-=!|>@n!1%?GED+OMc4mG+dP8V+)49Qu}` zY8CZWq3UZ;afhUel}z|njV9YjcGcG+;BP2z!%*HP z#hZh`ah%?wp}gfJgS)5~mbEazj?l&Cb)uGFNG7wZlT-C@bqf4*+m}7!pXY!{y^)mi zC@PihuRQNfh-c_xHi}^5F186?{nr)J!F&zxm5Gx_3{j8qg!rb_0+xK zfqC-uWH8vNtP~~c?er=(B3^jJE0V#WcaVAPQe2W1v^?H{2D(TUWwf@=xg^ro>Ry4o z)}h)u3+AY{{{7=nbrcPb&eGOZzYIk}72uUB?&^*HCs5gbJeAfcDR`F|x&Pw{u}`|$ z8xUtV0}s01DunEQ@{;{3oW6|!zwshreltPWKzo`LQGMzN>eEkWmMA{D3f`eHtDrqK z!lpm3^y-;n9C@VjgIb4Vf8bOms&PTRAl-}t{VTo4%l{h4dXHBRa2T&ybx+=eZL znrfwEUGZo2wvuXquF&_v7LZ1(+s{S~C)O|g2b$W!#tV!(LY$Wt@tQP9z4+02tBzvm zkT3h0Lq{qSP_+z{J8iYx>46_ek_;8FDv!oC*2@3_a*ZOznL+v#N!PdD?MshfESA&e zYY!nQBMd}Ts^L=WoB#yLcl@Pp^|Ii=!qyb;& zdfs7vjqFotxm|J}Cn$;z+##8Fh00lj^_|t;gPkxpbT`ge(7{3&quyTQF&bClBx-Fa zJxZ$(=#Ce7yS*_e{aSsM&fczb zzGrJ!Rd!x+qSa;}G#Jj%B3bLcJ*?7~oD^#FFu@uIK5k$0z zqNSGT%weMVssLZd?h2i+B(Z?Tmm)>7nUV`F$qyd23MrW?N%M0CO3C}+fiH0d-mH{# zQpulDjjFhhMU>Dh98FNHEKp>ZP!O;SP~5b97uMHD*C5_iPPZkqQSV5o>r2z4r&xIJ0hf;P~Pi?=(m+{L^+Bjl3Hd2B&Juc#4EXGmxPLHHf<0Lb0@zdI z8!nAO)tC23hYa9TE&+VXr7@`b+8*gJ0lx=m3f8LV3mY2z0e>p!G|+I<4b7mvp#7lX zJR7hG!v|dg_@GPUDm3v1tb+YHpo>7GAvSb_E(cu$8dZePI0YJNW%yDbbZK1M=MOYB z5it$7RwlSt&t`pyrRwq}g9l7LScmVgDa@m>6k??cOVJpt#`oJ4ma4HdV#^hlrZJSJ zD>PqWUXA&QouM$l#!$+xP@KXtHI_x}<8O(5SsFv>yF%|OEJtHS#D1=@B8{O|aQ{nT zsQ47E-4)=#*-eLXtmJq|_&5Zcr&C`9n%G1Ei#@6q5WQrG)`f zzMxV_@)x;5=)tYAP@tOMtqC<67yI6;xI`^de$A;;EmF?A$^%_kq|C$e=Ri5!6Dm8X zCsc;2Q{C{C7P=|d0NxmWX+u7*fDczp2{<*JWQUV2IN1)*uwaiJ_E>O=9iC~yseqAV z;0=H9vLwH}hI44&OR!Wv394*$ebcnip9Xe*k;gT=2XkuhG6zKPY=;(!M#+>&&m)$I zS4140_)3o{f#*K71eQfw;*p31stlP>LJ#dWQ9K-?MRAg%Me{6CZze=hgZP?55B4j* zESzzm1*CGbR1(HGRBnz{0XcR!--3(ma8bZ%eoSYP)>e-6VEiv&1HK{gnd22yp!zNb zD6H|5@RrcBU2|UiWTL?}Sl#x|qPM)LMEx}o)n7F-Yee7R)+KXWB@65^t5JptE$EI^ ze!aQ@t_86Z)>V>e3D&YB*a}lGx5l+=$rq#SiE@M7sqX+|$v>)>9~)4lGlu3YDr}rK;CdX{6D5-1}eCzYKvUgm3Gi;9N2e0WzEEgq)|eRzp#nxB3Rh1L(Y zsK#BX^PXmv^>563Bjoz|h6c<|3LJuGB(v((@y9G>Iv&Y&$7%7YmU!Y1Abt+TcS1ZA zkhYs}Ck+U$eTz!;A<7PaW) zy;?5Wl3PN#$0#?MxsR9J-OJKd@n3yNiZ358RmHzjYnX0nxPcn-sNr>Bb=#kbsk)xm z9l5whRi*K|V=b!#e*$~gvc&uY++n{tTin{pw22vv796LKAa>SwHTCiPV} zK6ioa=r0`{PwvfI}2R>-cZ1En;VLTejWJp%(n{;&K0 z_II8Ez^?g9+1otNlf9YyT&1jUFYjI+NdBSCuA8CkNMd8PrR5(1e4ns!l`6I>v78vb z@t_p?BBgw*QjSJ*zkG!hx_d8fX&DDv?8*}&mRhGpI4n|o0o&&(1FLFr_E&?_;|Y7& z`RU_X6s?(U@z<|PS>R9lD|c2~T&m2{ZSn5s!p91nugvP*dp*qx+0D8Yov8m;fYDa? z@}aNgKne-uvmM&Fk4-$7@;I9Ii)3sQ#{IMo?p%wyX@Fc4<-*lT>gM9gz~5H}1`b>U zA*;oIM4RE_0pGE@?Z?KM&2oh@u@5HR|3#^}zP&{>vD_~F7QExg#gGeE>*kDBav{il zNy&xwmQt?OF1MRU#EWrMe*vxC-jb4tK{< z!@*kGpDbRg-aHAYPlDA6XjDzXt-K^8v-8#Mk6}zE;KwdUNinbBo`4=6`(SnG0IIwH zSLj>*#(L3e&I0luis*>|X;eh2(JP-3#eUBQrSMCls7@P{dV+hp5nbdOa%;lq*quX%!NYn3*cl-}KGO-g?ggY5sclb<#u(T4Mt z4OnG$g}$ls5qqA7IJ9CEiBOkL-n5#MRcWDx>7}n{9i@;C}-VwzK2H3k(_pznpAZV z#II6Tv)6>so6}_r%|c!YeoWSUbmDiHc%bLdzB6eDGd)<#dKsi8Jm3TOz4t4l8Lvg$ zoOE8O#iWCwth!0Q$BO|E68JM@C{fFT@o$M`m@Kz9=Rjb>b+CG`tAP)hfq+OxQS)2g3?xS)1 zL~-=_gRAIkeY&z`%E-P?Dg*u?56|Gi7V*Q*QM3io0;(pihf>t}Rl+DwG(V5%fY_CU zhPeJ>4;l)k9sd3pS%V=8mL{ z)v+QC)#0^Q$1WPhO%TfT_j@HSrTSrkN&uS6Fu=_d<^)`0ZcR2?Yd4B1p_{N zF`lSmhYajmFN7TBV$NpgwH8iwa{os;VcgtFI-J2U^o! zf^Nmo8evEt%J4nK&=z5U!FCOID~66EtjROAp$n~=G@gQ?X*9G+4HC8VUJR>T?Wm|8 zCvsH!04uQn5)zI2(FMbgZ~I~sYB{(XFG7(KMGfryQZ8JgD-^m%irohX9i1t!QJCBed*^8+BwfJu>-^G7L2K$mw zOMhR8-js%lu?CkFwjT6fw2Rw(6y%!$RNQQFA_d$BV00rO5mZI*1rz!v?#%@;5d`^x zc31Mg zv%rIfUpsi9++IIlK%E@94pJEDyF!76NDXaQ@jl|;VnOPB1NeW@EYG;(@Ok>0jNq(gb3MjdfA9i^t21W*ksHiV z*?&OMq0e1aXU_Yt#4~H@su_V#G6Ekj3;a1fJmnpK-C>9S;@?z%fMt2i4I9j_ZrT6O zQu+TCKFcF;_ERlbxdZxns+Eb8by`NkQqRsv@JZ;Fjuw(!7G~ z((26{3o4AFg53OqitLSBs|qR&VA**^#pRVoenC}sja;`H<;67xCE57}DLc4a|HL0*+nRlK>NvMP6TxlvG4URGIMQIJh2yVA%jt1hiVR(WM5Wz`kg zo6GVGj7_=4r7BicR8de_R92F2no>|xRZv=4TvnQ0oDW?f@(c1s*GTG1D~*lCRoc2) zmB%%X@)*x0o>`UJZH)ZfywTl_iQ;k*UpsMoQy{_{@sAU<^DvR&`iC~^FlNjDO#PKr z6?BEFt>p!t%HnNyFCHRFqOh!Db1s_7tn$=IbY3JnKN4LKi7t#p7e%6rBhibDa`afV zfAP%~)timVqTF&cdVXd8NuxCXl%|cDJjeI6y_F}c+f%~jytMb(iqffz9!>z z7m;QzEvxb@NL%QEz(tGG=-W0u1^J?hbyrYfX(_D8-CPhi0w0Sql#BJWwzRUkyu7TU z3fg20@W>c22X0on31c<-o#)o#k`m8GINj#*l7h_z=;!&K5)9iFBid7ud#m)7p?R78 za@Gwu&erc zKg?+8SmtX9U6R!JeG)kF$5lt#^_9?qr;;FM}3twG+Ciu6Ly%>~yZFLUJg%o_=uKN7fLByizK z;G&Vh#Up_iMZjh0OJSiA>tRGqP)KA2#-gqD+JHqsnQaK|ABxcUp$IJ>iqPz#2yGsU z(BPp6trbK~a3&@5oJpwZ&ZIc8+2fe}Oj0q*9B4u^(a2P2M>r$eX_+kj7Q*?_BqGz~ za74MD7>`NQOvT)3M%5H*QkY52C?-@hs(7-~htW$E&32o2iNRpL3Km?VCn}G%mQ!7G zp*Xi%(JAM){66h?zb`fWqv~IrZe#*d*OA>nr3D_O%T|qi`2~3;xpMHZ1wrn{l7h;i zOt6c5Yq+?D8Puyg0Qbi@xvI)VQBvm@T59#tjs1LUbHV0H^JH!_mbY=ns)CA=;?iZ1 z9;&~%6srT4(XP}o00$AClCrXLd!mxBDyzyxJ<-Z)UA;qWs=aG&I(Id)3y*BfD>-2g zov$PN6!O})IVrQMXLFCi8GY5tB~shi0kd&*lc^o>X!rsC349$O4k z2o;>{Mbp!9;))6=*8B`Q!@sA zB^UU<0^YKhowtXkG)7l*V zlYFfm*FWJKVKO^m{^mKZbTwUJC-T>!^@T&;e`1fdIRM|#e#Bl=j3eY4v&YEo0N!Z8 z0JaGOLltg4NZ-QrS-cs3961%Bth##;2d%V$KXs&MAEye3-U8roivBnP-_WDo(fObN zr{6p#(|1A0I>&=EHr)TvgL84A8cA|XIN)r>UaPng$8T{XN4I zC59Uz$HORbN%of9l4?}taLe)w3VFzAOR$~FmY1OFXrd)$C2p44!z{ZlhB~z>-k4oo zRb0Y>eW?FL#&vTX=6rhm=sVo+FwQd>Zw9@8h<;($7Gg>PbtDFKHZK4OO z6@(=EIhH`SnF+g zo4F=OcV?KjaWTcQ71&9N~k9!r@mD-u_ZJJb-X~ zcQ~Ac$DRK2N;u5_b?lcv3y0SrJofW&xC-Ik*TUfk5yrj|4nKo19pPIDpT~1M#}ID& zML0agZ5Yq?qMQhC{x8TQJoY=tBh2p$ho3{puPO28*mj-as7Z3179SnMPh%$mn}NUX z;&AvvGAxTuB9@B3_kclEelu}hhQG|ha5xio8wp9v6Oyk?9Di#}t#QTlOV3*{^K3Fw zR|)=ZyeS-B$5##06O!(BE}byWwKf`AO8UKkn{Nq+`8lpg`kPkzI8JdG1|RUA37+58hr@^BZ9JLxyY7n$y6+uV7wvjHUf4ZI&IE529%Ksgtzl8BZJ`-i;?|Rxw{|xCj_Fz0i7?Hn78lCyiK>cpRc+x(^ zzBbFg%aESu|ULabtNx()~_fLh^ksUxFtXV8 zy?dNLA+0WYMS{09AuT;2H9a9^NrGodLh_P?q$LS4G7dcoJuT2f*E{(;Spz3);A9P) ztbvm?aIywY*1-R*8mK+ZD_LjikV`QBhKEmb?Svn<1N@~<^Ge9i6Yv+)e4GZxcfpjsAK5dA(ujE#MziBEkGADT@X5t-5iZ;v9 ztSc~9^PBnOwP7hwjph$)+N|#ZO~0F{^l9<`bHRa}5%Vh4?Y%{ZckA#W9e!7b&+70c z9lou@_jUNO4#y>XC7-D}JXeQ{b+}xI*XyuQhg)=bw+>n)oW*a(&jFjo9daLI)7g3qInBFDc9i; z%%5AO@C)WIm~GgY=gptHa4rr<*l&1F!hv8#`b@`y@_F;-EijDNbbe;YS3%{c_}mrM z>W=58yu4u<8^&;6p0jVnaok9}rw`LxUQ&%SZ4YmqUqXQkv@qGsKCWy%Z^boVGR||O zBb#G`#-(c~4$*r)?r!DXoQ>P#l|_azc}UuMd4<{K6=i(76i4VBpvsx-!b!%2G z|FR)(_44Z(@{@Wve?`X1B}=oiveQ?u_JQk~t5+j&m_5-Pd(81n={!q@k72sXHshTM zbt0|LK9AQmZW1tj$5Z{phO<=Ja4uhhlXNDG)}}4GP0et4JDqG(_JNaada|FQ6REy+ zvY%q$Hpdi(dQ3by_MRMj|Ly0~o|9`Nb3FK$TO)Ce$8|41X}Kc(ydn0R?fMJdzFen8 zct>6z43{~%20OW~R&(XdlY1rUV0iMoPqyip_Zt5)w%Hhf#&>dh9mKq z>&UB4u%0y6k*DZ&;vB4XWB}7oQQWPc`asYD>o?qBlOcb=ED}lgcSdk7nuC*1&Uvu?;gfWQt>-3G5KpZEB=p8Sf4*$Zt_=dSN!wM zhgqo9_EY+|tupx^yTdD~x3JTU@KgM^;1;r~&#CoZ;gSz9jljPJ_24!f!aVIsFr3b( zQSN~DkvwBuDtyQJ_B0gNh>D3`!XPSo1%l+5C`Zgjh($T06TlSZ7{^yWqMYt;A~-e5 zjTdo@aht*EI{(zIBJTbK!MHg{cFj4B8fCxgdPtJT%|nH_zIGZ}qrXpn$GDrpn#lO{ zkC8)f)VvtJmE!Wj;HU-Bg-9@5EJ)Pi*hdk>xYC$%kq}9)Wl$KECPcD}kI_e6EQH6! z4iR;U5Gk(TkhoNcR97msT_!}DD}&lD7sBhhh-_XV{I2g&Te=XLuIorF5hBawXB{k? zx)$6yu2ZOO`IL1aid?DG<`=8WU0bMar4UuFdzo_O_=!5UdH?aZ0vP{0hXH}{f8YfU&EP}WJARXjyBIH$cyt^1 zllUegMR z@k^rwel!C2BG0(xj(8U65aB%#bEYFU(Qva~CS2-BpoWi487Hk0r6XMocPZ<1qtcj+ zxbsn{cCx`m5^ASmM?Ai2oT$B+9MtbjC&wzp3^)Ie?eWWF#n!bJ163IA@4%+<3!_B1 z#7r~XDTv1BIYgu`0+&Nm{N!X+Y7=&{usW-JL=#?Baz8N{j7j$+m&9En_PT|-4^i7J zr{o>7;4>aTH0Eig!(EONB&Mo5n~H))GE+HDx)t0Bw~G!h)1~ku)Twdi)iA^`L#=oWo)@Xq##l~5VM3q{EhY$Y_ z$%p&S_DZt69)_4>_hopBFm4*t&P@m4+WB~O+z(;HH$2S6wX>xzDq49??%)+&^X}hBsl8?t^C~~VK9tC`_6#h@NUj zL^X+Oe;MXpsmazI4vzS%G}*Gl5rfoBO~N^*p}tpZ63!8Zs_Qk`u*1;-*)MCGnr?S& z2lG0eTDxQF`T=-`a*qvm_qfq?k4Ml1+3w9!8+~69_t>J{WAOI)b!T}|TlncFhdu=<4#~&0bKrI`iGwgJY5yyXvtEO75}yPkCt#q&%Ike( zmHZ^QPhSVqxbhml#@>j|GES|o#;MiSIJM{+r#nG~;B3w> z%vc0Sufd|8BG>Gxmys(*)?iUwgE{A%wiFOr0`Z4Vtz(>PFz44!V|;qd6x!(8hYRxK zQtULwqcWh*l{}dXl&HIro9omm`HcUF`1C29QlmIUyH1;O58@NcqoTN2alD1XM!91c zHyjs1Flt;9ZHjU%ArUP^jAIJfVuXlytYS*65J`?K5^+LIapaL0FGRAVltjD`GaOq< zOc283c#TAY5HlToWi~2Nh!jVdDM>=iaXd|8q7bQ$Zx%zGEI$o+&Ivj!Q^*geWm$*g}=4;pnA^xQwXBsqHM+ z$DmG0cARrB+QsoAF!xN|5Jyl7_bd^Qa?FG-_qjsEI5_3FzaT`sDWheQiWLKh-1n;A+j95BQZbrFl5#{I7Pb`#IdBeIsQls7RK;@yEy7NM7BjSAAtBv z>^G3ISmcu&vE`7tNQfyIs9908Oe$)eqG_DaPDRr`p{Jwc$a*j4O+fq;INBJeR(GO} zSqdDbq(3p~GmNPDG%?M!1NNR${fw2EV--R@$54N_#V0Wp9QI(WaYWl@Piat`5;#Eg1TWgIp)@9CEw$@r{taPWe*7cH2j#FCeOG4y3;lZrGEY~==WE6L# zIk+v1P7@;8!EIsm z#X?}xXUDljh!h96h0&J^k?P>KF#0kf(j43tMqe(3*THRJv{wkfgWJOBbRjYw+!jVJ z5hBaMZDI7Xss95za~!8o+wv)Y15xDQwlLZ+R+l@tEsS0%M3sZv!ssiuAqc?~-tqyJrqi>Am(BJ0ZwlF$7ZaLbo!@+G~bdK28>EO07 zdSlEiD0sn$;j;omlKagoV5*>JIGrw}-U+rs$91jZ*e$41MFa25ufST$Q14vuB9u@jjPBV$=?oDfMe zmc@=2B3Z_=*mxm4GM2?o5F$m!ve*P^vQ!z%ViSc(ld&u|NeHiuWw8^5@XJ^hJ866- zGR>5+EOxSJ%aXAyc8U-=GM2@jB1DmlWwBG^)`QC~is&{UX(Htpn!b=<6a7l|s%_ zT!lcf!uTs~`wQY{CQQLK{y&`)>i}^tSv)64 zNhAJKT*tewVv=02Y=rtlypSP&DRueEhl+CSH6|ZGW)sd&povXPXT*7w`svX|{Oh)H2w_n@`3HoH;yD&M zu;CKZjRZP){JqXZ@_d0X&l5yKT`pnmBy^DL$4(LUlZ%z+WEDDPY@1pGIGsL z@=Xtfj@^UU=OsP})$68F!nLzuM)KhnV_M-xW8Ed>bL||w-CY3QZ0XR> zoon2`flRKZGTrQzg__E6bJWe%8xC>xhTm0veN866^ zne)BK+%S0b!rxRR#1$Lcl2{by&Jtt%`xpRHe6*`dzb&`0Ku`fXxn3Z&uPW+-y zbeG_y_a_N#L)XsM9qv*T__-ui;FcZkdlL*}f6@m~vMKpne3iPtTcm@F-~rF)yST;jRXa$7pLvE>pkm6qGmu`LeYY%(UrP|Uf->vp1b zCQan}$F=1rXaQt0O*Ph*BKIqxPL%=0xh2Q_5~%5k(#N)BjeqcbFY-5x*>W|Er=buP zGeuR*7BtT57kDL&%O(DL!QuWTl+1}|KXGm8*=8g)&h<)S44jQWw*ysjX*|29Fc@c1 zTtqKapMX^dRbo+o0jM4!#TLpH%LQiro#xvVU;8V;EQa2j{q?gCNxY z!5J-t+CMmBgi!kjXRHuv|KN-hLhT=%r_De z6F3^0<)~D+xyTbZN=bW7`V3=Ak<;ak-2#7+CA2GDy98%{*Agj+T0*;)3Za(Ju4O`~ zCA7;YgjzzomjAEzz6DIK;yUwo->&Z4@1FNV4`w8R5TF^2UPvIp2tCk9LJ~;e5fW~V z=AjvDG&9Wf2#H_`Bpf?&Y$NR0tSt)+@!GKwCc7jH$PWz0!LgID-Zj{FOrHDOP?(B#*;ut$&KCTV7W*rUhr1_9tg z$LK=4y)GFU6Yjpy#5r#8!up^gtPdJ6)x5?D>*It*eT@^=#|EH)rTgBN|A+!H9u=tf z&0<<{ew)M>k9K))M6=?HN0-I8qtd>3bY=X@06g)%sAJi0~z?Tbg(3ZQ-QXtw~`7muzJK>Om+YXs1~cyvSKZRn@=#iN_*?*O2E z@#tphwf4oMJpyQ7Jh~kM8j90yXW6N3YMG2B3ZM z=$7gz6PioUpd04XW> zq%BzIC{AsLh!*rgtO(xkW35^-i91J*kmN=@KN61Unc z(@2(n_Q0JRy3rxWk$0Bi89H+Y<u%UlQ}p#KQU*_31wwM+|!>tG51I7yHU|`u8>dk55;nKq947w{zp$Z7pycrvSlRy z7M=enJO{;IIW+Dxm-nJwZ7v@J8Jf%ToAb}(eDUARC1$0fx%7(W(yL-Fy`s7F{uRw- zeRIg2AO9v+nKobxf(GnDQP{?ST_k`pU<(B>2JB)1i~(CDfH7c~1P$1w9-A=+>@x2M z0E_`!?D4|V7_g2+7V=~aSf@}k25gA{#(;GRU<}yOcq8f<1GdZX8JFs^G7k!6|fZ{(vm--HDP|(JA z;O(WrbDbCu;@nj(&HAru1%Df4trcXt)C#V^a;Y3KH9?@z7-q;;9J3I z0KOIM1vTFa4g>J5;0IC6w}P}wz7?b$_N^eh<6FT&)bXw09ss@-WZ!%%NYh)if{!4} zTEVzj!5-u*qDAo7D-jJK*C8DjD|nbGv4ZpwO3fv#Ag4A%`)REp)5Z!Wcn)+t%q~3x zY?L3y3No3{R*>1>w%N&|75oWt%ybgk3Nl>-jTWV0jy{Kvq;CaDZz1!fjS?%!YMX7A z*7okfIj+llLF|YUpFOy zKKgaj0_dY(HxnO5d-~|t%?hB8e%+h^`smlK5kMdPy0uAKCw=tm)(JIz^y}6OppSmt z1_AWZuiKcYM;(3i>oy5Bee~-#3!smF-4>~%kAB@&0qoK5KY~-P3o{wz(XTrzfuvd$ zNxuzr<>WV#$uRB6$!{c^cn1J|@*Bwspih1yH3I09-$<CJfiRzi9$EP#_8uV-*O~ zz5?O#qOU**_zHx8uRsX+3WR{KKnVB>gn+L=2>1$wfUiIZ_zHx8uRsX+3WR{KKnVB> zgn+L=2>1$wfUiIZ_zHx8uRsXwRH8tb+^s}`FzFv%5!k0hfiSsWi2`BLKe{5|D-Z&s zPL>>R0Ecs&QFHZ;11bhZmTHjLeUVrvghMn4LJe47Umiu`HO$Z&B$5z7Ymi7%0IfkH zDFL(wiKGS48YGg5zZJx^28m<^&>AF?6F_T_NR0qmgG6eR%h9OTAdxzurZq^UUI48@ zA`Jp)4H9WgtVSKJK_X2;O>2-yvjAFyL|UYd)*z8q0iZ!RU{`M3_`++sJc`V6888{k zsl;KjhIeQxnPJ+IyC0Q`zXfT}ao>#xMuYscy9N0*yaI{h3WWK;3xr%!ItktYE&E5n zH}CI8j^pe_IsS#t5L<_r-8-RW%^@saUL1G|B$r*tD_+KJMgIZSSLN2BJOb&WS!7-j zXT9+0oyigBDp|3oH#_bma4zTFB`U!%?-a|~rT^zh^DlJfR*?3tVE%k2{YFz)lr&o7 zH_FJNx_@2Zw%fJdcUtY0?@q?s-I+< zXM##!tD8H#s8;2Q!L`xvr5OMh)xotbl$9uhYk|vAn<6lYH$3V;p==DnwMa)EHVJs(KUUnP_jh*7r=bw_NLcCfZxB^*s~qE!X;c4OOoMYdK2XZul2p)wZ6B* zb1_AF6Xji>tplJpQQn^PZ-ao|M0tCg<{(FJqP%@A3jyd&ly{4CM{lCMH^w<7dK2a4 z6J)*KM0xwAZ+a8u9q=e-pK}zC663KJ&WuERdnVdD!l>s6(K2)FmCPKF-$#x_dq?|ob zYN}4CX`7m=7eL$8RD%H8rluMb9D%l}sV1SOZEC7n0BuuKEmB9@)Kseg_aLwl`dHBy zPt9^uNM~22(|3^}ym3uuGE6(-jHk1S-vpqY@pMiA?TlkD!W`|4r)ve!&Um^megT-M zo$++N_aKNZaUwh#5V2SE!_y7!93a$dFaViY9pi@5-$gq6l@yid6UdWTf5-cGTu0Z0 zvws8h^F(toIUc`)mB?!J_boasUp(>{$)7_cKdZQyepBUD(*Isa8fYb&%h-w0)lWC` zrZ>zFC-QcXtK*)aW?7iwo?(u_i7^l)wP+U+9E%fcNn*9<7|$7gGbrf~Arae%-qqH> z+t1p7KI=dcDX9ycMt^E+8P2JzN})hLLnrETf5v?FG)yb0yBOo$d|l?d6|%ggXgd3r zu#8e+Xkqfx43%1^KF!T&pfi5oofsp&>yzEg_py?4VqZjO8*;q92xL*EY5JTLok2|< zzQT^z@%U|qMtqxrCEoA%=V}(nIUyt=^g21wm}toO>VS<$~WqW@wgTxpL1gbmkbm zz=ltul??OU(`P0cE=S!~Uew`8Y{FfQytzpdg6rz8L*C-7bnx_M_qvGVbQq}HU4y(X zj|5Ti_T<2L!C4`ihpuW8KMm`w7Nbr7*kzzkcbr1ZC=~Y{Xl0wU!mnz$Z$@+1XSwR! z)6XAs9pv7S;}YSao%>f9&@S(g^!J_^|;Ge;F}Hjo#QT}f%h6xFCBLoQUOk3bQo$_%Zhh6e}#y;G@Ufk77heP2G0>q~ZOa1D@NK8_=OSvTeav7-ZX0{#Djp&CrNA!}tJd+cONN{WFYD1Mtr< z2>53h1pG4$0{$5W0sjnxfPaQTz(2zv;Gba-@Xs&^_-7ad{4)#!{uu@V{|tkGe}+N8 zKf@s4pJ5R2&oBu1XBY(hGYkSdGvZh=xjQ3{6_frM27!GUajcl!pApB3N&gIkfPaQT zVAP5J2RuHGe=&Zzj?&>bh^OM$FXl2=>BH=JAp8dRiSz#wQfhA#^%O}s%!N4;_HPpj z__v7!{M$qV{%s-w|2C1-OgPM?9-HxR6aN-~f1Ai%kAIt(L2v!rL{jr_6AAdYi3I%H z#0J#aCk~RkEb%OIbYMSj6S*7lZxgBTewdKkL>XHyl+c0wy3?A4?3u7Is$q6c;IM|- zKY?4pVu?kHUI-Nb2|5NgODvL12%8jiMAzPC;ki!S+$a8L^cQhS-M<6fVWW})({N32 z8rBQoM6Z2C6Tlrl|;ag zN(xNFPBRS~VQCPR#5wtXLPsSry)Tr|QAq^86iVo*Bu>_va6(5Vk#p<9GFvxE2lj_$ zw%#BBqLSh!DybI*<0dMJqJM#>^l=Gd8#9oxC>@p5W)4VnR1!2Na^Bm*Z=A(V zR1(uJmrIUc2yM5aNylK>?4>NfrwJ{H4}>PMlz%Bpz`v9w;9trTXp{2OIZTla-M+DBm(}WECK&gmVkdLdoTLwU&_*R@GoWAYyVP~fPX3bJOKYv_8b8J zQkK7*=wHe*=*7R3eHeg$Da)?`_?NPOgdG1;_9+1Vr7XMSU&``F%lu2(`vCZtvh16G zDf=wyd=6HM%P`jRcgUJ&LX&FNVp`pIAm1fg)*E{z>kY`aAYC(niFE&fDLJ$}kCYVr ziYPB}U8z@N=KRCxj#ry}6^-g$saGe|^sdya7eMby zy#@jFuGDKx{1|oguGDK1YI;}dH4C73rCy8F(YsQwRREmya%sC%11@!2ocmL6mis+C zl#bd;^LycOd@r2y)rr**rXYqnm0^Mnj(A!*rW?6`ODqfXY&guBcNQE%GJ)`|Hxfk> zP9vTAc-mz!mQZlg+!Q3RDPWbi5>4t(lLYqjQd)|InQ~kz&@=$?Jg7j!{u}2>~Hls&d zi#@uCd-%}Lqpe4DDful*^gVRu4$z9c7aaKcLiU=G1+}M9cp^n`$*sD){Jy1>|0K)5 zgz^)MMQ%?&cHCq2$qdW8r=L3R)NTR1HpA@Rab2G?&cD!^k039?ZPD6=6c}zIgxpmf zn%w7(MZSn4R~zuDW0B7R>|RL8!w&11^mW~0G7dYeW8R05tBp0jr{Mh&pbZ||;EpQ$ zS<`%@Y5q5nF>A!xr1?CY`X460TRMkj$7$YDr>7Y^#nj(V=&Z|w1rF3$InWyJaZsI2 zg9vA^b^t(H#%>+;;@BU8Q!isrFEV4lL&lz2V#a=lj6G|>r|yW{0&2NMTsj#09WwTs zPBZp9WbAdKFYVatJ+^_d-;w?9Vcm5*_LIoK*c8u=39-ll!PYv*EL%MjAqx41?6 zpj`{|UK;rVqIoTieE)F2yvRZO6$iXSsB2=q%u8wN=~m#SG)cM@(PaRlyoyS5M%bH- z)^pKIkxtUBh`xa-x)sqrd`Q9HKtc-EIZ@7D13il5+cU)5_tEejER8YVrJ1+V#5&Mo z>04=HGv7+n#EUb&mFB~EroJcy<>D;Hi!;2H=HCI;ycO$7MTS5;kCVPy z%I(5u+PxPgGwvp&vrdc+CvJ6LWhd`s`s1OOnQmqJoKAm>=}+kNB~1T;PG7-vpUd)5 zUiz6g3KaFOc_~WGh^>(4~X}dP4fQ2&(kgc0C|}MdMMCwW)#dT z4#kPv7u>K%O)SNP(`sLE!(PQdiXM1p!_o>jY+)hde>hnlHeY??iEh+{3rYg`3!S-= z%Jn8xzIy&2qq{t5R3Arfw*enLq4t42>*oC)ip%%izJbEmv~lq6>EAn{czU*e9(%;2 zMa6Tu4W{lrCuZ>=F0^re2TH^KE1tYeP2RAR)SbwpmDwphzES)VH>QPl?0Wc!wU2<>oS&fUj2HOuUEKij%>|_S_eeV?GhoN; zIgmd4$&g~*>+X>2OLoYx@tB?Ww(y?c;|>`{i|ObG@R5L9#{D%BXi9ic*xE5qq6XQkFojVFIB{MT;iia~D_EELPAhM5V*ey9 z-bk!;l{B1LyrBxMkG}C#H$fag$OFsv0SsGQ;`Q@MgkOh_@TOzKe0H2y8xh`gY`l~O z`F-dJZ#p&^@YUlH-gI1R!0#N7@TOz40be>E;kjIokb+`!qgc~hy$=f|+^Bp63wv8i zhIM*4SA)!{Kfb$LdNvzh6zUV<#2cq#Pnd46(7kppCk1X5cGbuj5#bcuXKF4rW%k-K zL#E75C-$DQGAC@AQB$VZsrj}kv&7JmcBV~!H)eSqGDMF45Vb|%7CLiY!canK(K-L^ zE|kLGT|SS`L#63$hvD%@Peguz3hApiqa5vndmdmmN7C3y2xD@FG5g&Yke8dQ+0-j+ zS{XGAi7h_ajXI8FIdeUlk{&ntJ&qkc+07!3-A7E@G7C%@aPQfZ-7Ml*?(rpULg$h? z&EcI+%{Fj^2565Q?Q)!z$}lLKf&Vk!LWD*u|P$ulpFFcveHhIO>8$ zqS~KRgSGewD$Th9@<6p;{;JNm&c`JD(qUrFM#mop$?!irOsvI=d=M2)XjlW&zn0Lj zRvQ{dzq{dY*+gk**zW@sk=O)!m>&-@3M@?r^PEo7zx;$w(!KlxNlKtk;|3Hh2_qx< z$p7NU2(o5HK8s|ELpcFZ?z>#`j+l6t7X`<~oW+B|Wbu{p`%pm}wD{!$Xp0tKC4e?* z@znxon-;%90BzLbR|=r5T6~QF+N{Ob3ZU&;yjuWm*y8I1(3UNJjR4xT#WyrwfPQM* z7T;7)9jT35JQz$C4+fLPgTZ9+U@%!c7)%!5;Vl9+ZQ|nBXBj}MZCpGUOcvkUv>rLy z%EkA!@aq@a%*Ah!?r1v~e`B1Js102_pCIe?;cq+`Ocp=jF%jFgz=U++PcVQq@>^hTM)ryoZ3brX z2f>cuz{N>jllc9!C=-tTPo&-0-AG4b1=fm90uzn3;4>Cm z1&rq?l1ojvZzla+pr4sYN47wt$n|JidE>x2@^-UyFzzfJj5|vQfaq?krm?02o37brMRT2A-(5H%TUo?@wD%Bgu5v|8$SrF~vg zm{D%!Kz^vH@GFIy3Y&4f_n^zEkLzf(Tm8J7*#&+$-q$&%hjky{W(zp;cwP|23vtQN zT1L~|6MK6%(l7(a;a}*?*TAVbU6*_2A7z(MfAx6$T97-vfHQ;B-{Wz5$@ebeT6Ir< z>3E#+G4D2opE_PQbijGfB2t0lbUe)6`1|AJ6=I*le*{ABuhY=xFb@viKbH`Ftneeq z{6PFKrRF^+k|PKeIwMwv*D5?lcslvFlKHk1;UScLCQ0j$7Z8P)fLEV0nRlKD{}7qa z8t}E_;W#RN-hi(j$2(&j=Z_8eo#XYncXWda;(ss-{v}78FJwQ91dasi=a|gBHuFu+ zpVa8g{U{Ro2E-^u*=5I!yOCnAer93bcp$y&hPQPCjqou;35N>ULkXjIEzpd9+X-Rx z?h7@e?>rG_AkvK{_ch_{O_ylSVjSe`9>dvQ;p`s6*`31KJ;GVC=L_J+%@U{(KD}Q! zIcUZYu9K5PhLf9xlLt-aqneY$2K?v=;pB(`A2=bLe3Jq1J5m1~GemAs`3FuOwwweT z7})7qhnH~y{0p6F!7zjk-i3w@$K#KHW8Ml4-YMhuw(4=e_U158iE?J#`@=V&`!zln z_|7VAzi{^!<~ysj0i*0O60On1W^EJhwVHav!o8&i>JC4R0W3?hWBf*|aA>7)NW}Ch zw0OD6#WYaZx()ce7PfT;eDrwuJILK&NgbDY*(mKWg3p;xQ4z60i=pMXsJ)^+bY*gN zvZpTG3<*?DPaQguW=2xuS7G##1x_+~RnpBs@ppu-ZjoHII=Qf=r*2J42vwqufhurb zvN$L3NXrX_dg@pr-VWNGAeK<&%_gNI$t%_B_L`o$t6SEzK**D!noun`m`0{o(#s6) z-ZLzdy-2#7yIdYM7=TmjcMpRqcCXI1+5W+>9c;ZNjDhIkH<-%8lJ@Ar7WSaK`3@Oj zV_hiOp3@y^cR8Y_n$U%rI&fuHh6Qs?I7i30F~kuhlMw7?o3I&nw4IEnz?V;^on(KCBE=rDhLS!7#Ufgq z{+OM`;=Bs|c4edmEhj8veYr~N$>i`;e%F($$zm-&X%N9AM?j=K*HcHC%lHLL1TAZ4 z(kGs?l2U^i(u{78v#DAuCv`rl5}~Nqa?^ln>IxZvuGeUaR}=#rhL?$B^Gq=a&cBw3 zSz1(QmrH}4ZFCHCJyRMkxCm3&=J#J%p;=aaev7l^+Qk>K)294ckLtA^E1i5#&!$_P z&A6VLaA0Z@ma$38DUWM6Ra|c=uEq3>smf@MXKgjAp7M2;D~cbr0o78?Ob#PRH@K+k zG<)l1Dn)To02(y!8;h&4sht1K#o=Sw&g6eb zF&kE`XnkQL(pJps$&&^K!t^ikwd{yNPK%!^s`#j#r=piNLpb84B9SQSWzbs%wVbpq2y-ZUMOV7A zcw}ZSz--YvS?}6f4(nlS2eEv8)s@MFw#eFUh*Q?UdAA;xxct6IH2K|YhotzvVY5M_ zL5&Vhfi~GX%XkZ|c8Q~OgXZxpi-K?))NEM_;Mbg)0ykF+@&$V7w-v z17W~2S;od|XMTY{Bw3KY`*5L;_hpUBr^=18eyWWDEH7g6g zwBgdwY|P3XKht?I&EJE?{qB^g6Z-e1`^Kadj+EwH+6r>UDjaK0D*Dv9nNxuKOKzlU zi@b+qmGZtm$oqzwyltD#aYcl&k%>#Gu8f->Mn^3?=M<>L$_oX zoYmSr9Wd-UyIhMtObLTaRDAjVOnWw3`)lo5Z)K)IOID*6!Ai#?MbW_(7Z-SI>H5Sr z8IxEpRljhPTxnIe*;U<6L7!J?Y0o!0mG77hJMV$`heH1g)-Z%WiU9tfn(TKv2S%sz zQ@3^YO-xL69_;V$>{{Bfykkk{s?O1o1A;iZYGr=q^2L*b1H*lV#iJu*(?=H{9GkWU zN5=X`rw0a|&grSiP6Kov7%5E6#B>&pO$-7bY;t&DXhmmNN7pj6S&5Y6uta`jY^0Ds zJXq-K=x5ib3IhX!Lmk5ynIlAz#2M&RVRE{^kl)m^Z6gpk?k%QJ13#d-82`p>SwTz} zF`HLROdl8>=|?_zws}QQ5M=#v!sfI^T>_sB}M78c!xn6*sl7IfZ zir=g}ub}XA9)EHkVC%j>zF-#Q)$Cs7qQ*sDy_&0&3y?I}c}TWu>}5zU(8)`YoUfBf zBriF~GRph9s((bOn^cSU7Nu@fjoxo6wOiGBZ&hlS%6e~8%Duf8iQhuvSg&evQ{h`f zNEdoljhpsPB01Ho8r+N|Cwo<$o0a6Py{gr%3-4v&!$j8$dbC$1+@=>)_HN~(@-3<% zyrN!t;m!4mFD(sCt6Dz5#724cs@!{2z1OQ20Svph7F09w7>HZ{0{DZ!PvV~nonLOa zta-1ZUsZ|wA5h7!gWs)>26%{>@j3j3GX4UdeT%B^RWWck>eVW>)%ya-zfrC9ex%eJ z(388#t(E#wubH+|Kk7B_R_aH+X5rE@PA;`9%~+N$vxx@px52BUy`XLqwQgLPb{lZT zWY$dx_6V_lvcXLXcDh$}7L#c=C0IH5|dD zE44?(!t)z2VG!upwD$;kU$Yky`yxT|>b%PBRW%T*d(^C3RO|`0I=sA5#h+A(@U``L zr6zT_(`3C)Hf$Zh=57 zd07OZOGSUAvgqzfmF+~&dKG?VBIb3dd93jUA_X< zIv9GkRPjQ48pVqgTg@N7wad_)(v^oM`wkD{S2u>$w4 zyd*OPXmrpo1}mlWv?{f~1>$By$_+26gN95&89?;fFneyNn$5?M2o8|52)#=+-~kb+ zA5pXa+N)Dh(XC%lsq;#mQZ+ZL+2J3C>QweQHTzuor~8Qa1vC=#KBRIU`Z?tkSK z6@vx}Uj-q55enGbZ!+}b3&jUix+%6d{CTvIInTvX%THwC2O}b(E|uT|I_lIHp|-D5 z&E65UprGovs91-pze=?g)Z#6w>#SO}M%AAyg0U-A@@AB7D3)$sTTIto1r@bbn-!?E z%qiu5N-YYntyi@}=<-&TfH9%X$=$4C1$7Bo)rli^JkF|%`0&;!E=2J0Vm_`^EqH*B zvA3wMy{h(Qm3yU($fYdTsTT5akEXRnL%*2TkA5+&lm91aVP5VBgH-JNr&art3U3pJ zcDpD%uTd>7sHQEx6fN4PmK2n`1%fC#FtbOgg1P`@?@^cbs>~LZI|zBXTP+Q*u2%~o zsncq{H>4I}G+R`%Q!U@CR-IKnz3QqL)WsdD{UCm9a7bP9q`DZ{Yt@{+s{O25-m6w2 zdySgYsoGyqS6``?g3m9gn#HPpSXX#XDs-xO`&6c&E?T2D6x5Q3)#f!6pLuIl=3ydt z^r#JM|9SZJYgOmNs%DjHKPD|*{G3Wo%YqBL{cT!FZxKBke!{Lb*PZ_)7g*?&=+N2l z-onn}YC7~^Ut?DHR!ej!HIS$&aYF-YQLD;Q^{G{*R@ML}2VJp1zsZYrdb-XnO8CKo;(3aPbssRbuh`XuV#il>_nuOzK0NVxkPe%&-0Qf&v7dNDk& zUZw9>ZKq8-^uUjmyWQ*b*82bL@$`Sw#HeNX=l0@p{`DUxbrJjU&fo8y@(%t>{`>!^ zB8G@T;;jt_!!CRbeq|x-bpC&_K8%I_e`tmDU*CEDTnIaN zXb=2arol>FpE)_qoq9;`fhVrC} zpJE!OHU6V=WU#=@bm|m$6WrR#3c5`!%r}4G$p1Bba_v-4OpZ_BtYvy)LVMwrtOwZR zTZ+mYWvu|EQl`SFXr|h?^-|)aaA{>XTu`ZLm3u(d-VNMZ0txJJ@8;$Tok6CA}hmzdVo*;)8U8ZFT(;<%4y*UR2q;RPqt_c?r@VH|Z-t=V8-- zmVa1f9#M&NDztS(c#)!)S`bdu1UPZGf=;;T1v+FXY|KBz-p=H3qiS!BrhNWyER?o-)3^N4R;# zCjaCRC1)rPY>z7_3}8!DFcAHtBPSb1azoIAp-X2X9MhaWa{6_j#F63wdpW(A|EE9?190y?JIyv5nc=yX5Gjc>liS?lHuwY(0aF zS6+F=TZ?10PpV7Lt0uq61Q?0ebVWjYWIaEIsS7*&ide<R z%6cAe#d(N&R?Wjv<%=p4zPM2za6YI{J?cLYYy zoQB5SSubN%oK$T%A$k$5&1+PN+q4j@UGYn_&f}u+jMh7U4XrPi%Z95yr5aDFxlgDX ztQ#II->QRQOz?^^}hhM`XP1UU8?m-RkKY&sgV4Y52=NBso7XRMVu)HT~Nd= ze@M;03&(Ca5%KFTg-X%A^-Z-IrADR-RhT#c?E*+!i&n0Y&fLAX%|Ol93W13kxYf>HK@4{ ztHn5q9pXTttaUon+5K-knZXm;0^Scz8pgXSs@ScPd+Gl}_9|#1f02J0xC;Njbqij0 z^=+L;_ya-bQEt!6Zo!MrD{{3tvu}oRTSIWdrm?I}syRng9j=C7R=C2ZT0aO^XwJfYj_`yo7+G-G~Z2jsJQpyITibaYB{2^yhiWv z??cQb`WICD%_`mt8uu6)y#0mmM|v&$N@}@pRJGxY>UmilJEv;9swUbZrwO2$(x@Czc--s zcXUZH9a^el?E&f`v?{vi_rZm*^K4b!6X3Fmo(ZakUr8GU3H>4+6Wjv__vMat>g`rg zrr%CEW}m8{7++IF{7ZJhK`jHel}ZzYrFgkqqJU=XG)r!=v9YY+p95REKL&y_UUI?) z+~yTUeTFV+1!li~*@_8&MLg`#S-D`wc2vjk?0Zqo`kGn@_Z$Ax9+POr)!$jQY>T@5 zth!2H*`75wxcbW0#g*+ZrAWGCnHR2#g{@ESVm{hd{6F7iXd(|RDc_1T;*rrq1JS;?n zk@s#j$7|~`6<*dAE-)LDN3qz$=jFrfP5Pdc%X&m}NB~bkh1~YDD^w!9xJ5;=!)4eG zhMMt)RpMb4-vhAmX2jb(x%Jd3Uan^L63_d7kdXU+Y{}U`ua4_@Sginr>nLtf;O+$| zsK%`%RQ8B%Blna0!I?+MnHo8*Zr-CB&Z?S|YSB5^v|e?|EAl`z04*F`*4bNB-4-=} z8)gilOkk7@=Q`c9dvqYn$Jk5n6Z|9(aP=SC%l$eD=Kfj&1jxc!-lx>udw4Q1x5tos zSv7+c$b1|}2eBn!z7BKAKdI)B5`wDuI4h$Je^5h)r9)upg=fVI<@4i1L-~S}@7a-; zMKe*Dbn^YfIR0|_ho{F5<@p8j{M7LHWC1}OQV!4jfxf9hXLNk*V4HkQk4=pn92*>H zgJy6Tyq7;XIX*p+pXe(LV?|wygD8~GBe<`yaygpAy3eoA@9N4QL@Of`rKNY~*KgZ} zh?L#yc5U39U$=h!#$CJeJsVK=+U+;Ct?%k;(~*m9iw_s3#|GCP92^^*9O(zxH`zbD z7Ez3gS1xZ`e6VftjwNl2p*Ys|qt4=?zOla1W48}Z2KvqJvM<}$?e4j0V}8Sq8?V{6 z5e*rAGI+Ewh>?wtbL(?4Ld;gIMlD^HEw4&L`qjG|X0 z*pG=TuxpcpgCLmaJPl32;ueOSvFXG4fxZG}3t^gpk#5?yW8H2Hl=FVu0`-2|Tv7T0gOe%2Q1yAJWYDyb zdnLlQ{)Ua~c5l?eHZgK^a5O(KI8hijbDyV)6Zst)9q-eN1~PXDB9+(ADMt@FKQRt@ zxMqBO)bY8AMKy^Acj<9q77tH=JDtPhhX*@v>p!$?)$(O4J2wnY9V(1Zbiy(%9bRE3 zgi@M6Qs_GX1{nD;L}ai$Q5qT<937altk)7gFpePC!Qial*t4CJE^{%_*FWfpfDa5p z0C6TeRp>iBp@&Mb;ljjt1}7(F!S1wc7(Eakz*rl;SluB?fdV6cgJx8jXq+QIrUm|farm~{zFhH(#SB^qgFIV%BHYT z$0zfneaFV9jWGEOVsvCmPnMQ+plL$OG-oM~&KZ*po-qVV+PJbRNbU~ZkM!CR*X z$NC5JnA`&p*+}&LdN?h5P>Lt92gYdLY)a$v{XY%v7DwSp?Dyr`Kh4Vs35^I z;-T@$!&ssIP@I85hz2{&P(;`v@Naso05)j8iC%+5qg>%AKcH{eN3!--C!h+5m@3j; zQcQLglgo<9<;CQRVsd3MdAXU?u9cWn+ds%~*{H{~lAA>5AP^3W#NZ(;fW!UJjK*3) zH%_3>hbPS3I2fu3oyiYcGY&C-)bJjn5m-FVP+@R%RJbUzw^>#(tlmM`a!QkyNTG1d z86O)xCPpzo#>t$RhMkc`u0@(2wvo)iqa#>_`H`vd{?)7VQ&atYV?z$iXgWip|Iq>6<02QaGxbMI_s8j*JlG#Z ziiZHFBR?S;A0+a-*6-N4F~4oc`gPklru-CK2|6&vylc1ZxCWU+#-Gv-6U0XDLA6u` zCqfvUAu1&4if__lf|Pbd(K?hZEZ5-V;lY6s0^+)( z!0!C6-5c^ZcC8eb*oRjx_hI8UYp;R@`YE6^%t0A6ZYr}7@iIzZl_u9Xe5RFEhN$+( z=$z$)&e-M^{lkNh*dv3J^vC_~!>7u_sEuRc9+WPx=bmBX4L9t#!5JuRVcAl@-%{v? zjk`A9aMQ*O`K~3!nnh$+C8T(x`LgQEDwSMO0a>YbrOL}I)U8BsRfTe^Vb~7C3{1(k zWpwb!Al)d<)onf7x0Z1=!0zBii*s2z%9Rz`y1a^LPQ zrjLcjhwRd#3dUZ>SMd7YwLh?);I~a-4Y3=$^1C)}+qiyre&-DvcW&IiA&7!>aU>>K zqF?%A7VH4zJXjR+XtXR|%rSyUNfm#}jZHy30!2pO?OFiN@{oczg>{`F!kCYLRn-PkZTyX5l$=`WB_o7@MO z_5^F#)3g1ib=!K#o(){$y1#_jy4}@TUal+Um#Q5$`%jE8-*0qmfE{m^Q~+pyyqOvRl>)e$1CC!&d%CO<&(~m zrb_sfv$G;T?L5$0seH!q?x}>&I?WaFIp@qLDwVHs9)GkFzSep5Q~RCrKi8>qUaN?& zcbrdGD&OF|`k6}jM!W~U628fK{Iiwt&CW{|@qEe4%sC8&~PvTCn68^F(c)panQu*O3c)t9-Qu(t6Up`*`U<%9sxQq{fQ3d}~gD>Y#Bd&rf z@wr_t`_j%!W%DxM;B&LO(ShRMN`v27hTjH!$Z2*y`pkYQOtIl#ui$6uPyR|l*hxEg zmeJuaR)n0HdiZ0&SL*-yD)^_X;QzD=os_ zORM0k%_DzlG33-Zqkq^fd=Gw9>d!SOkN1wuu#Yziotbv(kd&{TVF&Lp_;S1XE}=8i zKCZwUUc=5zf8ZXxqqEJKX$S8Eom$9=jlh^=1nWN-{GA)RWvJiAOI!K(oWa|#YT(@# z^2gt(sx|50<3%YS#OU;2Rl$GP&@cZ%jMu7^PeyhB9iy*MO#WsG-T;9|mnmQV8;2XJ zlz$`eHCT7nPXHU`?>$J6Z&n|68vN~s{>}Tl1+&+5=u{Q@?=a<`UZTtY6JY)gV;)Jr z{I?wMt3u~Pz_&@w(vL^0lz+Mko<&QtU zLpt4MbiQct`^)fuBXo4#;3t2@wi18%3sIHu{867u_ytBj%ilwO1@JZawIJ)yL(R%x zPZc`5tKf&L;BT*je<$#{3i{^*Qau(GiYF7%rgtP$HRl(n6=-6*@{W<*) z{0$j=`ESGCVep%8>XvfLjQ)8K@RZLx%jEFiOL-|;^6?2nr~LKmpRZD$ZxQEux8JXP z#R%4a2R?^(%lY{eQ@;GSf0KB5ekFOHTLr%qc#i9VvT?1iQhpop@b|3$Z0*H>lutY5 zKX&yShW=A!^xtFfFO}i>t9X_A|Cpg~zoGqEV^5!{Ql8&`C*K}@W`D`Ne8tcy|Apf3 zSD^z}K<359)2%YpvVt!mEx@cQ_$5{F8x4K?wv97}q1RU_e>3o$FXx&4(jJzZ{EZnp zFU{)~_^Z%^{JX0Pop%~KZO`myG5mmx{ySTxJbztS^z$?OrJybURF(4owF>?f!NadU z+%0tYgKYf!2Sb1VGy4hp{mE4Ei}=%3vL2t=&*FahrNC29mamu9Rp@N5g5OgGe>?E9 zUY^;{X8m@5t4jGZf=~NDsAYd&;4y=@-_4?(lRtS`SVspRE0=fnPZqj5#+{D7v9a+3 zxDVnD4Ni5-V4Tnol;b*v#|z~+maByCm>wG)IW#zWtYU>~nH_S}IXzLaQkA?8xumSn z{jv;HFO2l#CLGsj!SR;jOUGTBS31tpyqSC`&9A_Z(gH$YCSOVm&E!vMz7PRwvJm89 zX_?n$ix4PfXntT+GmZC5hSbE!pzca>qN)|691V^R;oWW!v+-TU3P8?~y&{essZ_Rf z4ob^c%d5cqvWheLUMw(^=f%9r{4VB~@w%8%iO+eg&wgCTO>4HuG!|KqFUv0BPaty$ zjGi$!#k!Ksx=;gC1zbjADIkUiH^Wo7PRth&Lxku+1dZhL1LOIFqvHo~gEN5Zm8pE+ z^ijE}8pWmMK*y5GC2*rNHlnXQFvh~9e|0{6`0z1QF_+?mWSAvIXGG8Oo)sPBMTrS8 zU@{OyP<&4nO3k?b*O&VhE^GaUNF3GdrILR+l+SOvVcm5b^SDFG=h1CMG3GaJHptBz zZgBGY4m!VM(c$`(r|wVGyBbG{0fb_I20wtbd(b@XEm$Wl<5hhV$=* zb+ldC#hJu}ba!97t>>Ec`K298J651OzKn66{NS$AQkLC;Yw_y$TlS)|QtYQ6xKX^r zmdOwy;2n|<7s%%i9!9*Tum{{`JW6SYByy${RTh*|%)A^yI3tB3%wcmMSE=GFvwVu|SJ9WxaYXj2kR1YKC#mtr)a z)`%F(fhoMhM6QeFdcHhN5lrbnR7#}s{jo23HcrHbgI9J2>}`B`bdZ%-i47?YR;U`@ zAfZIXp-G^lS+IeS1AllnN=Jfe5fVg+Dji{2xEol{J8ua!fbcN9tF*jnjIqBkVJ1#R z^p=T=0|hNzI{dY?wvjTfB)g`4f(#(%%u9@pAKPMrrb>7fT-ZYr8&KK`sFVh~7VTn* z*7oPo50lryVl$|f#0}*K*>xL`US2j3<^9XXBk4#X9r{=#haeFn?Aj{`NV~+hja}S>mfC48ie}}k6?p! zkh>>*bVvi57}l%Pf#{#Z@Rf8Y4@{4Y4s`St5cP5Z5i-agz^gb9f?6M<_>Df4#$4&kF%!HTo-;V!QQ~w%6(8kN`G>398nR#G+#!8g)?>B&B6Nb%x zT+I^v>K*^eBR%ZA>s-ehCP$zZn+JeDvR4W%VCu?UsxOT6O;5w0_!8 zThGF8MIzX~jpy<1(IwKhpm~<}{~e~j<-ffrXg2jvm4%{M{#mlWTUOu32c7wZE-{;( z3;dP0{}A$6#I|qah#r4bS9-jxLV5e=P%MLgmd*Cw^wm%4`sL*YA9y~(`1&HZKzWJ zbAP2Pyf1GmR;k}!rT*S^x}`XN{Ui9Nu| +#include "mib_header_MQ1.h" +#include "mib_header_DAC.h" +#include "mib_macros.h" +#include "mib_utils.h" +#include "mq1_quad.h" +#include "mq1_single.h" +#include "read_mq1_headers.h" + +typedef struct { + MQ1_fields *mq1_header; + dac_rx *dac0; + dac_rx *dac1; + dac_rx *dac2; + dac_rx *dac3; + void **rows; + void *data; +} framebuffer; + +void allocate_frame(framebuffer* fb); +void free_frame(framebuffer* fb); + +#endif diff --git a/include/mib_header_DAC.h b/include/mib_header_DAC.h new file mode 100644 index 0000000..68f13d2 --- /dev/null +++ b/include/mib_header_DAC.h @@ -0,0 +1,35 @@ +#ifndef MIB_HEADER_DAC_RX_H +#define MIB_HEADER_DAC_RX_H + +typedef struct { + char dac_format[4]; + unsigned int threshold0; + unsigned int threshold1; + unsigned int threshold2; + unsigned int threshold3; + unsigned int threshold4; + unsigned int threshold5; + unsigned int threshold6; + unsigned int threshold7; + unsigned int preamp; + unsigned int ikrum; + unsigned int shaper; + unsigned int disc; + unsigned int disc_LS; + unsigned int shaper_test; + unsigned int dac_disc_L; + unsigned int dac_test; + unsigned int dac_disc_H; + unsigned int delay; + unsigned int TP_buff_in; + unsigned int TP_buff_out; + unsigned int RPZ; + unsigned int GND; + unsigned int TP_ref; + unsigned int FBK; + unsigned int Cas; + unsigned int TP_ref_A; + unsigned int TP_ref_B; +} dac_rx; + +#endif diff --git a/include/mib_header_MQ1.h b/include/mib_header_MQ1.h new file mode 100644 index 0000000..e28a092 --- /dev/null +++ b/include/mib_header_MQ1.h @@ -0,0 +1,90 @@ +/* +field 1: header ID (MQ1) +field 2: sequence number of a frame +field 3: the number of bytes of the header +field 4: the number of chips +field 5: the number of columns of the detector (x) +field 6: the number of rows of the detector (y) +field 7: the pixel data type (U01, U08, U16, U32, U64) +field 8: sensor layout (2x2, Nx1, 2x2G, Nx1G, with leading spaces) +field 9: active chip(s) during the capture of the frame, U8 hexadecimal repr +field 10: timestamp +field 11: shutter opening time (seconds) +field 12: counter 0 or 1 +field 13: colour mode, 0=monochrome image, 1=colour image +field 14: gain modem 0 = SLGM, 1 = LGM, 2 = HGM, 3 = SHGM +field 15-22: threshold values (keV) + +DAC of each chips contains 28 entries. + +Header extension + Single / Quad +field 51 / 135 : MQ1A +field 52 / 136 : UTC timestamp (time in ns) +field 53 / 137 : shutter opening time (with suffix "ns") +field 54 / 138 : the pixel data bit depth + +The remainings are null bytes for padding. +*/ +#include "mib_header_DAC.h" +#include "mib_macros.h" + +#ifndef MIB_HEADER_MQ1_SINGLE_H +#define MIB_HEADER_MQ1_SINGLE_H + +typedef struct { + char header_id[MQ1_CHAR_LEN_HEADER_ID]; + unsigned int sequence_number; + unsigned int header_bytes; + unsigned int num_chips; + unsigned int det_x; + unsigned int det_y; + char pixel_depth[MQ1_CHAR_LEN_PIXEL_DEPTH]; + char sensor_layout[MQ1_CHAR_LEN_SENSOR_LAYOUT]; + char chip_select[MQ1_CHAR_LEN_CHIP_SELECT]; + char timestamp[MQ1_CHAR_LEN_TIMESTAMP]; + double exposure_time_s; + unsigned int counter; + unsigned int colour_mode; + unsigned int gain_mode; + float threshold[MQ1_FLOAT_LEN_THRESHOLD]; + dac_rx dac0; + char header_extension_id[MQ1_CHAR_LEN_HEADER_EXTENSION_ID]; + char extended_timestamp[MQ1_CHAR_LEN_EXTENDED_TIMESTAMP]; + unsigned int exposure_time_ns; + unsigned int bit_depth; +} mq1s; + +#endif + + +#ifndef MIB_HEADER_MQ1_QUAD_H +#define MIB_HEADER_MQ1_QUAD_H + +typedef struct { + char header_id[MQ1_CHAR_LEN_HEADER_ID]; + unsigned int sequence_number; + unsigned int header_bytes; + unsigned int num_chips; + unsigned int det_x; + unsigned int det_y; + char pixel_depth[MQ1_CHAR_LEN_PIXEL_DEPTH]; + char sensor_layout[MQ1_CHAR_LEN_SENSOR_LAYOUT]; + char chip_select[MQ1_CHAR_LEN_CHIP_SELECT]; + char timestamp[MQ1_CHAR_LEN_TIMESTAMP]; + double exposure_time_s; + unsigned int counter; + unsigned int colour_mode; + unsigned int gain_mode; + float threshold[MQ1_FLOAT_LEN_THRESHOLD]; + dac_rx dac0; + dac_rx dac1; + dac_rx dac2; + dac_rx dac3; + char header_extension_id[MQ1_CHAR_LEN_HEADER_EXTENSION_ID]; + char extended_timestamp[MQ1_CHAR_LEN_EXTENDED_TIMESTAMP]; + unsigned int exposure_time_ns; + unsigned int bit_depth; +} mq1q; + +#endif diff --git a/include/mib_macros.h b/include/mib_macros.h new file mode 100644 index 0000000..19cf76f --- /dev/null +++ b/include/mib_macros.h @@ -0,0 +1,47 @@ +#ifndef MQ1_SINGLE_HEADER_BYTES +#define MQ1_SINGLE_HEADER_BYTES 384 +#endif + +#ifndef MQ1_SINGLE_HEADER_NUM_FIELDS +#define MQ1_SINGLE_HEADER_NUM_FIELDS 54 +#endif + +#ifndef MQ1_QUAD_HEADER_BYTES +#define MQ1_QUAD_HEADER_BYTES 768 +#endif + +#ifndef MQ1_QUAD_HEADER_NUM_FIELDS +#define MQ1_QUAD_HEADER_NUM_FIELDS 138 +#endif + +#ifndef MQ1_CHAR_LEN_HEADER_ID +#define MQ1_CHAR_LEN_HEADER_ID 4 +#endif + +#ifndef MQ1_CHAR_LEN_PIXEL_DEPTH +#define MQ1_CHAR_LEN_PIXEL_DEPTH 4 +#endif + +#ifndef MQ1_CHAR_LEN_SENSOR_LAYOUT +#define MQ1_CHAR_LEN_SENSOR_LAYOUT 7 +#endif + +#ifndef MQ1_CHAR_LEN_CHIP_SELECT +#define MQ1_CHAR_LEN_CHIP_SELECT 3 +#endif + +#ifndef MQ1_CHAR_LEN_TIMESTAMP +#define MQ1_CHAR_LEN_TIMESTAMP 27 +#endif + +#ifndef MQ1_FLOAT_LEN_THRESHOLD +#define MQ1_FLOAT_LEN_THRESHOLD 8 +#endif + +#ifndef MQ1_CHAR_LEN_HEADER_EXTENSION_ID +#define MQ1_CHAR_LEN_HEADER_EXTENSION_ID 5 +#endif + +#ifndef MQ1_CHAR_LEN_EXTENDED_TIMESTAMP +#define MQ1_CHAR_LEN_EXTENDED_TIMESTAMP 31 +#endif diff --git a/include/mib_props_supp.h b/include/mib_props_supp.h new file mode 100644 index 0000000..1155140 --- /dev/null +++ b/include/mib_props_supp.h @@ -0,0 +1,18 @@ +#ifndef MQ1_FIELD_ITER_H +#define MQ1_FIELD_ITER_H + +#include +#include +#include "mib_header_MQ1.h" +#include "mib_header_DAC.h" +#include "read_mq1_headers.h" + +typedef struct { + const char* name; + void* data; +} info; + +info* mq1_fields_iter(MQ1_fields* fields, size_t* out_count); +info* dac_iter(dac_rx* dac, size_t* out_count); + +#endif diff --git a/include/mib_utils.h b/include/mib_utils.h new file mode 100644 index 0000000..798de47 --- /dev/null +++ b/include/mib_utils.h @@ -0,0 +1,27 @@ +#include + +#ifndef ONLY_FILE_NAME_H +#define ONLY_FILE_NAME_H +const char* only_file_name(const char* absolute_file_path); +#endif /*ONLY_FILE_NAME_H*/ + +#ifndef NUM_OF_HEADERS_H +#define NUM_OF_HEADERS_H +unsigned int num_of_headers( + FILE* mib_ptr, + const unsigned int stride + ); +#endif + +#ifndef HEADER_META_FROM_FIRST_H +#define HEADER_META_FROM_FIRST_H +void header_meta_from_first( + FILE* mib_ptr, + char* header_id, + unsigned int* header_bytes, + unsigned int* num_chips, + unsigned int* det_x, + unsigned int* det_y, + char* pixel_depth + ); +#endif diff --git a/include/mq1_quad.h b/include/mq1_quad.h new file mode 100644 index 0000000..907cb1a --- /dev/null +++ b/include/mq1_quad.h @@ -0,0 +1,12 @@ +#include "mib_header_MQ1.h" + +#ifndef PARSE_MQ1_QUAD_H +#define PARSE_MQ1_QUAD_H +void parse_mq1_quad(const char* header, mq1q* mq1_quad); +#endif + +#ifndef PRINT_QUAD_MIB_HEADER_H +#define PRINT_QUAD_MIB_HEADER_H +void print_quad_mib_header(mq1q header); +#endif + diff --git a/include/mq1_single.h b/include/mq1_single.h new file mode 100644 index 0000000..696c6ed --- /dev/null +++ b/include/mq1_single.h @@ -0,0 +1,12 @@ +#include "mib_header_MQ1.h" + +#ifndef PARSE_MQ1_SINGLE_H +#define PARSE_MQ1_SINGLE_H +void parse_mq1_single(const char* header, mq1s* mq1_single); +#endif + +#ifndef PRINT_SINGLE_MIB_HEADER_H +#define PRINT_SINGLE_MIB_HEADER_H +void print_single_mib_header(mq1s header); +#endif + diff --git a/include/read_mq1_headers.h b/include/read_mq1_headers.h new file mode 100644 index 0000000..261c449 --- /dev/null +++ b/include/read_mq1_headers.h @@ -0,0 +1,83 @@ +#include +#include + +#ifndef MQ1_FIELDS_H +#define MQ1_FIELDS_H + +typedef struct { + unsigned int max_length; + unsigned int* sequence_number; + unsigned int* header_bytes; + unsigned int* num_chips; + unsigned int* det_x; + unsigned int* det_y; + char* pixel_depth; + char* sensor_layout; + char* chip_select; + char* timestamp; + double* exposure_time_s; + unsigned int* counter; + unsigned int* colour_mode; + unsigned int* gain_mode; + float* threshold; + char* header_extension_id; + char* extended_timestamp; + unsigned int* exposure_time_ns; + unsigned int* bit_depth; +} MQ1_fields; + +#endif + +#ifndef ALLOCATE_MQ1_FIELDS_H +#define ALLOCATE_MQ1_FIELDS_H + +MQ1_fields allocate_MQ1_fields(unsigned int nheaders); + +#endif + +#ifndef DEALLOCATE_MQ1_FIELDS_H +#define DEALLOCATE_MQ1_FIELDS_H + +void deallocate_MQ1_fields(MQ1_fields mq1_fields); + +#endif + +#ifndef MQ1_SINGLE_FROM_FILE_H +#define MQ1_SINGLE_FROM_FILE_H +unsigned int mq1_single_from_file( + FILE* mib_ptr, + unsigned int nheaders, + unsigned int detector_frame_bytes, + mq1s* mq1s_h, + MQ1_fields* mq1_fields + ); +#endif + +#ifndef MQ1_QUAD_FROM_FILE_H +#define MQ1_QUAD_FROM_FILE_H +unsigned int mq1_quad_from_file( + FILE* mib_ptr, + unsigned int nheaders, + unsigned int detector_frame_bytes, + mq1q* mq1q_h, + MQ1_fields* mq1_fields + ); +#endif + +#ifndef FILL_MQ1_SINGLE_FIELDS_H +#define FILL_MQ1_SINGLE_FIELDS_H +void fill_MQ1_single_fields( + MQ1_fields* mq1_field, + unsigned int index, + mq1s mq1_h + ); +#endif + +#ifndef FILL_MQ1_QUAD_FIELDS_H +#define FILL_MQ1_QUAD_FIELDS_H +void fill_MQ1_quad_fields( + MQ1_fields* mq1_field, + unsigned int index, + mq1q mq1_h + ); +#endif diff --git a/src/framebuffer.c b/src/framebuffer.c new file mode 100644 index 0000000..fc965f6 --- /dev/null +++ b/src/framebuffer.c @@ -0,0 +1,40 @@ +#include "framebuffer.h" +#include "mib_header_DAC.h" +#include "mib_header_MQ1.h" +#include "mib_macros.h" +#include "mib_props_supp.h" +#include "mib_utils.h" +#include "mq1_quad.h" +#include "mq1_single.h" +#include "read_mq1_headers.h" +#include +#include +#include +#include + +void allocate_frame(framebuffer *fb) +{ + return; +} + +void free_frame(framebuffer *fb) +{ + if (fb->rows) + free(fb->rows); + if (fb->data) + free(fb->data); + if (fb->dac0) + free(fb->dac0); + if (fb->dac1) + free(fb->dac1); + if (fb->dac2) + free(fb->dac2); + if (fb->dac3) + free(fb->dac3); + fb->rows = NULL; + fb->data = NULL; + fb->dac0 = NULL; + fb->dac1 = NULL; + fb->dac2 = NULL; + fb->dac3 = NULL; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..0c6ca62 --- /dev/null +++ b/src/main.c @@ -0,0 +1,221 @@ +#include "append.h" +#include "framebuffer.h" +#include "hdf5_init.h" +#include "hdf5_init_meta.h" +#include "mib_header_DAC.h" +#include "mib_header_MQ1.h" +#include "mib_macros.h" +#include "mib_props_supp.h" +#include "mib_utils.h" +#include "mq1_quad.h" +#include "mq1_single.h" +#include "read.h" +#include "read_mq1_headers.h" +#include +#include +#include +#include + +// Declaration of Marco here, temporary + +#define MERLIN_DSET_NAME "MerlinData" +#define COMPRESSION_LEVEL 9 +#define DIM 3 +#define NUM_META_FIELD 19 +#define NUM_DAC_FIELD 28 + +int main(int argc, char *argv[]) +{ + // === start get and check arguments === + clock_t begin_total = clock(); + + /* Now this can only handle one .mib file + * TO-DO(near future): add checks to see if more files have been provided as + * argument. TO-DO(further): handle multiple files + */ + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + /* Cut out the filename from $(filename).mib for the filename of hdf5 + * The output hdf5 file should have the same filename as the .mib + * i.e. example.mib -> example.hdf5 + */ + const char *filename = argv[1]; + const char *base = strrchr(filename, '/'); + base = base ? base + 1 : filename; + + char hdf5_filename[512]; + strncpy(hdf5_filename, base, sizeof(hdf5_filename) - 1); + hdf5_filename[sizeof(hdf5_filename) - 1] = '\0'; + + char *dot = strrchr(hdf5_filename, '.'); + if (dot) + *dot = '\0'; + + size_t len = strlen(hdf5_filename); + if (len + strlen(".hdf5") < sizeof(hdf5_filename)) { + strcat(hdf5_filename, ".hdf5"); + } else { + fprintf(stderr, "Filename buffer too small to append .hdf5\n"); + } + + FILE *mib_ptr = fopen(filename, "rb"); + if (!mib_ptr) { + perror("Failed to open .mib file"); + return 1; + } + + // === end === + + printf("+++ get and check argument done +++\n\n"); + + // === start declaring variables and get metadata for the .mib file === + + clock_t begin = clock(); + + /* Please check the struct framebuffer from the header files in /include + */ + + framebuffer frame; + framebuffer *frame_ptr = &frame; + long ptr_pos = ftell(mib_ptr); + // printf("pointer starting position: %ld\n", ptr_pos); + + char *header_id = malloc(4 * sizeof(char)); + unsigned int *header_bytes = malloc(5 * sizeof(unsigned int)); + unsigned int *num_chips = malloc(sizeof(unsigned int)); + unsigned int *det_x = malloc(4 * sizeof(unsigned int)); + unsigned int *det_y = malloc(4 * sizeof(unsigned int)); + char *pixel_depth = malloc(4 * sizeof(char)); + + header_meta_from_first(mib_ptr, header_id, header_bytes, num_chips, det_x, + det_y, pixel_depth); + int bufsize = (pixel_depth[1] - '0') * 10 + (pixel_depth[2] - '0'); + bufsize = bufsize / 8; + + // === end === + + printf("+++ declaring variables done +++\n\n"); + clock_t end = clock(); + double time_get_header_meta_from_first = + (double) (end - begin) / CLOCKS_PER_SEC; + printf("+++ Time to get header meta data: %02f +++\n", + time_get_header_meta_from_first); + + // === start initialize hdf5 === + + begin = clock(); + + /* Declare variables related to creating hdf5 files + * Please check the functions in hdf5_init.c and hdf5_meta_init.c + * Handles are arrays that stored dataset ids for different metadata + */ + + hid_t file_id, fapl_id, fcpl_id, lcpl_id; + initialize_file_and_plist(hdf5_filename, &file_id, &fapl_id, &fcpl_id); + initialize_lcpl(&lcpl_id); + + hid_t frame_dset_id; + hsize_t dim[DIM] = {0, *det_y, *det_x}; + hsize_t max_dim[DIM] = {H5S_UNLIMITED, *det_y, *det_x}; + hsize_t frame_dim[DIM] = {1, *det_y, *det_x}; + + hid_t memspace = H5Screate_simple(DIM, dim, max_dim); + if (memspace == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating memspace in main\n"); + return 1; + } + // printf("=== create frame dataset ===\n"); + create_merlin_dataset(&frame_dset_id, &file_id, MERLIN_DSET_NAME, bufsize, + memspace, &lcpl_id, DIM, frame_dim, COMPRESSION_LEVEL); + // printf("=== done create frame dataset ===\n"); + + hid_t meta_handle[NUM_META_FIELD]; + hid_t dac_handle[NUM_DAC_FIELD * 4]; + + create_meta_mq1_fields_dataset(&file_id, &lcpl_id, meta_handle); + // printf("== done create meta_mq1===\n"); + create_dac_dataset(*num_chips, &file_id, &lcpl_id, dac_handle); + + // === end initialize hdf5 === + + // printf("+++ init hdf5 done +++\n"); + end = clock(); + double time_initialize_hdf5 = (double) (end - begin) / CLOCKS_PER_SEC; + printf("+++ Time to init hdf5: %02f +++\n", time_initialize_hdf5); + + // === start appending === + begin = clock(); + /* Check if it is EOF each time + * Please check the functions in read.c and append.c + */ + + int c = 0; + int loop = 0; + size_t num_meta, num_dac; + while ((c = fgetc(mib_ptr)) != EOF) { + ungetc(c, mib_ptr); + ptr_pos = ftell(mib_ptr); + + // printf("loop %d: read .mib\n", loop); + + read_header(mib_ptr, ptr_pos, frame_ptr); + read_frame(mib_ptr, ptr_pos, frame_ptr); + + // printf("\n\nChip0 GND: %u\n\n", frame_ptr->dac0->GND); + // printf("\n\nChip0 FBK: %u\n\n", frame_ptr->dac0->FBK); + + // printf("loop %d: read .mib end\n", loop); + + // printf("loop %d: append meta\n", loop); + + append_meta_to_dataset(&file_id, &num_meta, meta_handle, frame_ptr); + + // printf("loop %d: append meta end\n", loop); + + // printf("loop %d: append dac\n", loop); + + append_dac_to_dataset(&file_id, &num_dac, *num_chips, dac_handle, + frame_ptr); + + // printf("loop %d: append dac end\n", loop); + + // printf("loop %d: append frame\n", loop); + + append_frame_to_dataset(&file_id, &frame_dset_id, frame_ptr); + + // printf("loop %d: append frame end\n", loop); + + deallocate_MQ1_fields(*(frame.mq1_header)); + // printf("deallocate_MQ1_fields\n"); + free(frame.mq1_header); + // printf("free frame.mq1_header\n"); + frame.mq1_header = NULL; + // printf("NULL frame.mq1_header\n"); + free_frame(frame_ptr); + // printf("free_frame\n"); + + // printf("pointer position after loop %d: %ld\n", loop, ftell(mib_ptr)); + loop++; + } + + // === end appending === + end = clock(); + double time_total_loop = (double) (end - begin) / CLOCKS_PER_SEC; + double time_per_loop = time_total_loop / loop; + printf("+++ Time per loop: %02f +++\n", time_per_loop); + + H5Pclose(fapl_id); + H5Pclose(fcpl_id); + H5Pclose(lcpl_id); + H5Fflush(file_id, H5F_SCOPE_GLOBAL); + H5Fclose(file_id); + fclose(mib_ptr); + + clock_t end_total = clock(); + double time_total = (double) (end_total - begin_total) / CLOCKS_PER_SEC; + printf("+++ total time usage: %02f +++\n", time_total); + return 0; +} diff --git a/src/mib_props_supp.c b/src/mib_props_supp.c new file mode 100644 index 0000000..981defd --- /dev/null +++ b/src/mib_props_supp.c @@ -0,0 +1,95 @@ +#include "mib_props_supp.h" +#include "mib_header_DAC.h" +#include "mib_header_MQ1.h" +#include "mib_macros.h" +#include "mib_utils.h" +#include "mq1_quad.h" +#include "mq1_single.h" +#include "read_mq1_headers.h" +#include +#include + +info *mq1_fields_iter(MQ1_fields *fields_struct, size_t *out_count) +{ + if (!fields_struct || !out_count) + return NULL; + + const size_t NUM_FIELDS = 19; + + info *fields = malloc(NUM_FIELDS * sizeof(info)); + if (!fields) + return NULL; + + size_t i = 0; + + fields[i++] = (info) {"max_length", &fields_struct->max_length}; + fields[i++] = (info) {"sequence_number", fields_struct->sequence_number}; + fields[i++] = (info) {"header_bytes", fields_struct->header_bytes}; + fields[i++] = (info) {"num_chips", fields_struct->num_chips}; + fields[i++] = (info) {"det_x", fields_struct->det_x}; + fields[i++] = (info) {"det_y", fields_struct->det_y}; + fields[i++] = (info) {"pixel_depth", fields_struct->pixel_depth}; + fields[i++] = (info) {"sensor_layout", fields_struct->sensor_layout}; + fields[i++] = (info) {"chip_select", fields_struct->chip_select}; + fields[i++] = (info) {"timestamp", fields_struct->timestamp}; + fields[i++] = (info) {"exposure_time_s", fields_struct->exposure_time_s}; + fields[i++] = (info) {"counter", fields_struct->counter}; + fields[i++] = (info) {"colour_mode", fields_struct->colour_mode}; + fields[i++] = (info) {"gain_mode", fields_struct->gain_mode}; + fields[i++] = (info) {"threshold", fields_struct->threshold}; + fields[i++] = + (info) {"header_extension_id", fields_struct->header_extension_id}; + fields[i++] = + (info) {"extended_timestamp", fields_struct->extended_timestamp}; + fields[i++] = (info) {"exposure_time_ns", fields_struct->exposure_time_ns}; + fields[i++] = (info) {"bit_depth", fields_struct->bit_depth}; + + *out_count = NUM_FIELDS; + return fields; +} + +info *dac_iter(dac_rx *dac, size_t *out_count) +{ + if (!dac || !out_count) + return NULL; + + const size_t NUM_FIELDS = 28; + + info *dinfo = malloc(NUM_FIELDS * sizeof(info)); + if (!dinfo) + return NULL; + + size_t i = 0; + + dinfo[i++] = (info) {"dac_format", &dac->dac_format}; + dinfo[i++] = (info) {"threshold0", &dac->threshold0}; + dinfo[i++] = (info) {"threshold1", &dac->threshold1}; + dinfo[i++] = (info) {"threshold2", &dac->threshold2}; + dinfo[i++] = (info) {"threshold3", &dac->threshold3}; + dinfo[i++] = (info) {"threshold4", &dac->threshold4}; + dinfo[i++] = (info) {"threshold5", &dac->threshold5}; + dinfo[i++] = (info) {"threshold6", &dac->threshold6}; + dinfo[i++] = (info) {"threshold7", &dac->threshold7}; + dinfo[i++] = (info) {"preamp", &dac->preamp}; + dinfo[i++] = (info) {"ikrum", &dac->ikrum}; + dinfo[i++] = (info) {"shaper", &dac->shaper}; + dinfo[i++] = (info) {"disc", &dac->disc}; + dinfo[i++] = (info) {"disc_LS", &dac->disc_LS}; + dinfo[i++] = (info) {"shaper_test", &dac->shaper_test}; + dinfo[i++] = (info) {"dac_disc_L", &dac->dac_disc_L}; + dinfo[i++] = (info) {"dac_test", &dac->dac_test}; + dinfo[i++] = (info) {"dac_disc_H", &dac->dac_disc_H}; + dinfo[i++] = (info) {"delay", &dac->delay}; + dinfo[i++] = (info) {"TP_buff_in", &dac->TP_buff_in}; + dinfo[i++] = (info) {"TP_buff_out", &dac->TP_buff_out}; + dinfo[i++] = (info) {"RPZ", &dac->RPZ}; + dinfo[i++] = (info) {"GND", &dac->GND}; + dinfo[i++] = (info) {"TP_ref", &dac->TP_ref}; + dinfo[i++] = (info) {"FBK", &dac->FBK}; + dinfo[i++] = (info) {"Cas", &dac->Cas}; + dinfo[i++] = (info) {"TP_ref_A", &dac->TP_ref_A}; + dinfo[i++] = (info) {"TP_ref_B", &dac->TP_ref_B}; + + *out_count = NUM_FIELDS; + return dinfo; +} diff --git a/src/mib_utils.c b/src/mib_utils.c new file mode 100644 index 0000000..5e808a2 --- /dev/null +++ b/src/mib_utils.c @@ -0,0 +1,123 @@ +#include "mib_utils.h" + +#include +#include +#include + +const char *only_file_name(const char *absolute_file_path) +{ + const char *rslash = strrchr(absolute_file_path, '/'); + return (rslash != NULL) ? rslash + 1 : absolute_file_path; +} + +unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride) +{ + unsigned int num_hdr = 0; + long int original_fpi = 0, file_size = 0; + + /*store the original position*/ + original_fpi = ftell(mib_ptr); + + /*move to the end*/ + if (fseek(mib_ptr, 0L, SEEK_END) != 0) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: failed to seek to end of the MIB file\n", + current_file, __LINE__); + goto restore; + } + + /*get the current position (i.e. end position)*/ + file_size = ftell(mib_ptr); + + /*printf("File size: %ld\n", file_size);*/ + /*printf("Stride: %u\n", stride);*/ + + if (stride == 0) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: frame stride cannot be zero\n", current_file, + __LINE__); + num_hdr = 0; + } else { + if ((file_size % stride) != 0) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, + "%s:%d: error: the stride of the frame is apparently " + "incorrect (it cannot divide the MIB file into an integral " + "number of frames)\n", + current_file, __LINE__); + goto restore; + } + num_hdr = file_size / stride; + } + + /*go back to the original position*/ +restore: + if (fseek(mib_ptr, original_fpi, SEEK_SET) != 0) { + const char *current_file = only_file_name(__FILE__); + fprintf( + stderr, + "%s:%d: error: failed to seek to the original position of the MIB file\n", + current_file, __LINE__); + num_hdr = 0; + } + + return num_hdr; +} + +void header_meta_from_first(FILE *mib_ptr, + char *header_id, + unsigned int *header_bytes, + unsigned int *num_chips, + unsigned int *det_x, + unsigned int *det_y, + char *pixel_depth) +{ + char header_buf[40]; + long int original_fpi = 0; + + /*store the original position*/ + original_fpi = ftell(mib_ptr); + + /*move to the beginning*/ + if (fseek(mib_ptr, 0L, SEEK_SET) != 0) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, + "%s:%d: error: failed to seek to beginning of the MIB file\n", + current_file, __LINE__); + goto restore; + } + + /*get enough section of the first header*/ + if (fgets(header_buf, sizeof(header_buf), mib_ptr) == NULL) { + perror("error: failed to read data from header"); + goto restore; + } + + /*assign value (skip sequence number)*/ + int n = sscanf(header_buf, "%3s,%*[^,],%u,%u,%u,%u,%[^,]", header_id, + header_bytes, num_chips, det_x, det_y, pixel_depth); + + /*fail to assign enough value */ + if (n != 6) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: failed to assign header meta value\n", + current_file, __LINE__); + goto restore; + } + if (n == EOF) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: the first header appears to be empty\n", + current_file, __LINE__); + goto restore; + } + + /*go back to the original position*/ +restore: + if (fseek(mib_ptr, original_fpi, SEEK_SET) != 0) { + const char *current_file = only_file_name(__FILE__); + fprintf( + stderr, + "%s:%d: error: failed to seek to the original position of the MIB file\n", + current_file, __LINE__); + } +} diff --git a/src/mq1_quad.c b/src/mq1_quad.c new file mode 100644 index 0000000..690f5fd --- /dev/null +++ b/src/mq1_quad.c @@ -0,0 +1,247 @@ +#include "mq1_quad.h" +#include "mib_header_MQ1.h" +#include "mib_macros.h" +#include "mib_utils.h" +#include +#include +#include + +/* this assumes the provided header is valid + * the header struct will be overwritten + */ +void parse_mq1_quad(const char *header, mq1q *mq1_quad) +{ + + int n = sscanf( + header, + "%[^,],%u,%u,%u,%u,%u,%[^,],%[^,],%[^,],%[^,]," + "%lf,%u,%u,%u,%f,%f,%f,%f,%f,%f,%f,%f," + "%[^,],%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%" + "u,%u,%u,%u,%u," + "%[^,],%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%" + "u,%u,%u,%u,%u," + "%[^,],%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%" + "u,%u,%u,%u,%u," + "%[^,],%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%" + "u,%u,%u,%u,%u," + "%[^,],%[^,],%uns,%u", + mq1_quad->header_id, &mq1_quad->sequence_number, &mq1_quad->header_bytes, + &mq1_quad->num_chips, &mq1_quad->det_x, &mq1_quad->det_y, + mq1_quad->pixel_depth, mq1_quad->sensor_layout, mq1_quad->chip_select, + mq1_quad->timestamp, &mq1_quad->exposure_time_s, &mq1_quad->counter, + &mq1_quad->colour_mode, &mq1_quad->gain_mode, &mq1_quad->threshold[0], + &mq1_quad->threshold[1], &mq1_quad->threshold[2], &mq1_quad->threshold[3], + &mq1_quad->threshold[4], &mq1_quad->threshold[5], &mq1_quad->threshold[6], + &mq1_quad->threshold[7], mq1_quad->dac0.dac_format, + &mq1_quad->dac0.threshold0, &mq1_quad->dac0.threshold1, + &mq1_quad->dac0.threshold2, &mq1_quad->dac0.threshold3, + &mq1_quad->dac0.threshold4, &mq1_quad->dac0.threshold5, + &mq1_quad->dac0.threshold6, &mq1_quad->dac0.threshold7, + &mq1_quad->dac0.preamp, &mq1_quad->dac0.ikrum, &mq1_quad->dac0.shaper, + &mq1_quad->dac0.disc, &mq1_quad->dac0.disc_LS, &mq1_quad->dac0.shaper_test, + &mq1_quad->dac0.dac_disc_L, &mq1_quad->dac0.dac_test, + &mq1_quad->dac0.dac_disc_H, &mq1_quad->dac0.delay, + &mq1_quad->dac0.TP_buff_in, &mq1_quad->dac0.TP_buff_out, + &mq1_quad->dac0.RPZ, &mq1_quad->dac0.GND, &mq1_quad->dac0.TP_ref, + &mq1_quad->dac0.FBK, &mq1_quad->dac0.Cas, &mq1_quad->dac0.TP_ref_A, + &mq1_quad->dac0.TP_ref_B, mq1_quad->dac1.dac_format, + &mq1_quad->dac1.threshold0, &mq1_quad->dac1.threshold1, + &mq1_quad->dac1.threshold2, &mq1_quad->dac1.threshold3, + &mq1_quad->dac1.threshold4, &mq1_quad->dac1.threshold5, + &mq1_quad->dac1.threshold6, &mq1_quad->dac1.threshold7, + &mq1_quad->dac1.preamp, &mq1_quad->dac1.ikrum, &mq1_quad->dac1.shaper, + &mq1_quad->dac1.disc, &mq1_quad->dac1.disc_LS, &mq1_quad->dac1.shaper_test, + &mq1_quad->dac1.dac_disc_L, &mq1_quad->dac1.dac_test, + &mq1_quad->dac1.dac_disc_H, &mq1_quad->dac1.delay, + &mq1_quad->dac1.TP_buff_in, &mq1_quad->dac1.TP_buff_out, + &mq1_quad->dac1.RPZ, &mq1_quad->dac1.GND, &mq1_quad->dac1.TP_ref, + &mq1_quad->dac1.FBK, &mq1_quad->dac1.Cas, &mq1_quad->dac1.TP_ref_A, + &mq1_quad->dac1.TP_ref_B, mq1_quad->dac2.dac_format, + &mq1_quad->dac2.threshold0, &mq1_quad->dac2.threshold1, + &mq1_quad->dac2.threshold2, &mq1_quad->dac2.threshold3, + &mq1_quad->dac2.threshold4, &mq1_quad->dac2.threshold5, + &mq1_quad->dac2.threshold6, &mq1_quad->dac2.threshold7, + &mq1_quad->dac2.preamp, &mq1_quad->dac2.ikrum, &mq1_quad->dac2.shaper, + &mq1_quad->dac2.disc, &mq1_quad->dac2.disc_LS, &mq1_quad->dac2.shaper_test, + &mq1_quad->dac2.dac_disc_L, &mq1_quad->dac2.dac_test, + &mq1_quad->dac2.dac_disc_H, &mq1_quad->dac2.delay, + &mq1_quad->dac2.TP_buff_in, &mq1_quad->dac2.TP_buff_out, + &mq1_quad->dac2.RPZ, &mq1_quad->dac2.GND, &mq1_quad->dac2.TP_ref, + &mq1_quad->dac2.FBK, &mq1_quad->dac2.Cas, &mq1_quad->dac2.TP_ref_A, + &mq1_quad->dac2.TP_ref_B, mq1_quad->dac3.dac_format, + &mq1_quad->dac3.threshold0, &mq1_quad->dac3.threshold1, + &mq1_quad->dac3.threshold2, &mq1_quad->dac3.threshold3, + &mq1_quad->dac3.threshold4, &mq1_quad->dac3.threshold5, + &mq1_quad->dac3.threshold6, &mq1_quad->dac3.threshold7, + &mq1_quad->dac3.preamp, &mq1_quad->dac3.ikrum, &mq1_quad->dac3.shaper, + &mq1_quad->dac3.disc, &mq1_quad->dac3.disc_LS, &mq1_quad->dac3.shaper_test, + &mq1_quad->dac3.dac_disc_L, &mq1_quad->dac3.dac_test, + &mq1_quad->dac3.dac_disc_H, &mq1_quad->dac3.delay, + &mq1_quad->dac3.TP_buff_in, &mq1_quad->dac3.TP_buff_out, + &mq1_quad->dac3.RPZ, &mq1_quad->dac3.GND, &mq1_quad->dac3.TP_ref, + &mq1_quad->dac3.FBK, &mq1_quad->dac3.Cas, &mq1_quad->dac3.TP_ref_A, + &mq1_quad->dac3.TP_ref_B, mq1_quad->header_extension_id, + mq1_quad->extended_timestamp, &mq1_quad->exposure_time_ns, + &mq1_quad->bit_depth); + + if (n == EOF) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: the header appears to be empty\n", + current_file, __LINE__); + exit(1); + } else if (n != MQ1_QUAD_HEADER_NUM_FIELDS) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: failed to match the MQ1 Quad header\n", + current_file, __LINE__); + exit(1); + } +} + +void print_quad_mib_header(mq1q header) +{ + /* Assume the MQ1 Quad header (mq1q) has been initialised, + * otherwise you should treat the printed values as garbages. + */ + printf("header id: %3s\n", header.header_id); + printf("sequence number: %u\n", header.sequence_number); + printf("header bytes: %u\n", header.header_bytes); + printf("number of chip(s): %u\n", header.num_chips); + printf("detector size in x: %u\n", header.det_x); + printf("detector size in y: %u\n", header.det_y); + printf("pixel data type: %3s\n", header.pixel_depth); + printf("sensor layout: %6s\n", header.sensor_layout); + printf("chip selected: %2s\n", header.chip_select); + printf("time stamp: %26s\n", header.timestamp); + printf("exposure time (s): %lf\n", header.exposure_time_s); + printf("counter: %u\n", header.counter); + printf("colour mode: %u\n", header.colour_mode); + printf("gain mode: %u\n", header.gain_mode); + printf("threshold 0: %f keV\n", header.threshold[0]); + printf("threshold 1: %f keV\n", header.threshold[1]); + printf("threshold 2: %f keV\n", header.threshold[2]); + printf("threshold 3: %f keV\n", header.threshold[3]); + printf("threshold 4: %f keV\n", header.threshold[4]); + printf("threshold 5: %f keV\n", header.threshold[5]); + printf("threshold 6: %f keV\n", header.threshold[6]); + printf("threshold 7: %f keV\n", header.threshold[7]); + puts("DAC 0:"); + printf("\t DAC format: %3s\n", header.dac0.dac_format); + printf("\t threshold0: %u\n", header.dac0.threshold0); + printf("\t threshold1: %u\n", header.dac0.threshold1); + printf("\t threshold2: %u\n", header.dac0.threshold2); + printf("\t threshold3: %u\n", header.dac0.threshold3); + printf("\t threshold4: %u\n", header.dac0.threshold4); + printf("\t threshold5: %u\n", header.dac0.threshold5); + printf("\t threshold6: %u\n", header.dac0.threshold6); + printf("\t threshold7: %u\n", header.dac0.threshold7); + printf("\t preamp: %u\n", header.dac0.preamp); + printf("\t ikrum: %u\n", header.dac0.ikrum); + printf("\t shaper: %u\n", header.dac0.shaper); + printf("\t disc: %u\n", header.dac0.disc); + printf("\t disc_LS: %u\n", header.dac0.disc_LS); + printf("\t shaper_test: %u\n", header.dac0.shaper_test); + printf("\t dac_disc_L: %u\n", header.dac0.dac_disc_L); + printf("\t dac_test: %u\n", header.dac0.dac_test); + printf("\t dac_disc_H: %u\n", header.dac0.dac_disc_H); + printf("\t delay: %u\n", header.dac0.delay); + printf("\t TP_buff_in: %u\n", header.dac0.TP_buff_in); + printf("\t TP_buff_out: %u\n", header.dac0.TP_buff_out); + printf("\t RPZ: %u\n", header.dac0.RPZ); + printf("\t GND: %u\n", header.dac0.GND); + printf("\t TP_ref: %u\n", header.dac0.TP_ref); + printf("\t FBK: %u\n", header.dac0.FBK); + printf("\t Cas: %u\n", header.dac0.Cas); + printf("\t TP_ref_A: %u\n", header.dac0.TP_ref_A); + printf("\t TP_ref_B: %u\n", header.dac0.TP_ref_B); + puts("DAC 1:"); + printf("\t DAC format: %3s\n", header.dac1.dac_format); + printf("\t threshold0: %u\n", header.dac1.threshold0); + printf("\t threshold1: %u\n", header.dac1.threshold1); + printf("\t threshold2: %u\n", header.dac1.threshold2); + printf("\t threshold3: %u\n", header.dac1.threshold3); + printf("\t threshold4: %u\n", header.dac1.threshold4); + printf("\t threshold5: %u\n", header.dac1.threshold5); + printf("\t threshold6: %u\n", header.dac1.threshold6); + printf("\t threshold7: %u\n", header.dac1.threshold7); + printf("\t preamp: %u\n", header.dac1.preamp); + printf("\t ikrum: %u\n", header.dac1.ikrum); + printf("\t shaper: %u\n", header.dac1.shaper); + printf("\t disc: %u\n", header.dac1.disc); + printf("\t disc_LS: %u\n", header.dac1.disc_LS); + printf("\t shaper_test: %u\n", header.dac1.shaper_test); + printf("\t dac_disc_L: %u\n", header.dac1.dac_disc_L); + printf("\t dac_test: %u\n", header.dac1.dac_test); + printf("\t dac_disc_H: %u\n", header.dac1.dac_disc_H); + printf("\t delay: %u\n", header.dac1.delay); + printf("\t TP_buff_in: %u\n", header.dac1.TP_buff_in); + printf("\t TP_buff_out: %u\n", header.dac1.TP_buff_out); + printf("\t RPZ: %u\n", header.dac1.RPZ); + printf("\t GND: %u\n", header.dac1.GND); + printf("\t TP_ref: %u\n", header.dac1.TP_ref); + printf("\t FBK: %u\n", header.dac1.FBK); + printf("\t Cas: %u\n", header.dac1.Cas); + printf("\t TP_ref_A: %u\n", header.dac1.TP_ref_A); + printf("\t TP_ref_B: %u\n", header.dac1.TP_ref_B); + puts("DAC 2:"); + printf("\t DAC format: %3s\n", header.dac2.dac_format); + printf("\t threshold0: %u\n", header.dac2.threshold0); + printf("\t threshold1: %u\n", header.dac2.threshold1); + printf("\t threshold2: %u\n", header.dac2.threshold2); + printf("\t threshold3: %u\n", header.dac2.threshold3); + printf("\t threshold4: %u\n", header.dac2.threshold4); + printf("\t threshold5: %u\n", header.dac2.threshold5); + printf("\t threshold6: %u\n", header.dac2.threshold6); + printf("\t threshold7: %u\n", header.dac2.threshold7); + printf("\t preamp: %u\n", header.dac2.preamp); + printf("\t ikrum: %u\n", header.dac2.ikrum); + printf("\t shaper: %u\n", header.dac2.shaper); + printf("\t disc: %u\n", header.dac2.disc); + printf("\t disc_LS: %u\n", header.dac2.disc_LS); + printf("\t shaper_test: %u\n", header.dac2.shaper_test); + printf("\t dac_disc_L: %u\n", header.dac2.dac_disc_L); + printf("\t dac_test: %u\n", header.dac2.dac_test); + printf("\t dac_disc_H: %u\n", header.dac2.dac_disc_H); + printf("\t delay: %u\n", header.dac2.delay); + printf("\t TP_buff_in: %u\n", header.dac2.TP_buff_in); + printf("\t TP_buff_out: %u\n", header.dac2.TP_buff_out); + printf("\t RPZ: %u\n", header.dac2.RPZ); + printf("\t GND: %u\n", header.dac2.GND); + printf("\t TP_ref: %u\n", header.dac2.TP_ref); + printf("\t FBK: %u\n", header.dac2.FBK); + printf("\t Cas: %u\n", header.dac2.Cas); + printf("\t TP_ref_A: %u\n", header.dac2.TP_ref_A); + printf("\t TP_ref_B: %u\n", header.dac2.TP_ref_B); + puts("DAC 3:"); + printf("\t DAC format: %3s\n", header.dac3.dac_format); + printf("\t threshold0: %u\n", header.dac3.threshold0); + printf("\t threshold1: %u\n", header.dac3.threshold1); + printf("\t threshold2: %u\n", header.dac3.threshold2); + printf("\t threshold3: %u\n", header.dac3.threshold3); + printf("\t threshold4: %u\n", header.dac3.threshold4); + printf("\t threshold5: %u\n", header.dac3.threshold5); + printf("\t threshold6: %u\n", header.dac3.threshold6); + printf("\t threshold7: %u\n", header.dac3.threshold7); + printf("\t preamp: %u\n", header.dac3.preamp); + printf("\t ikrum: %u\n", header.dac3.ikrum); + printf("\t shaper: %u\n", header.dac3.shaper); + printf("\t disc: %u\n", header.dac3.disc); + printf("\t disc_LS: %u\n", header.dac3.disc_LS); + printf("\t shaper_test: %u\n", header.dac3.shaper_test); + printf("\t dac_disc_L: %u\n", header.dac3.dac_disc_L); + printf("\t dac_test: %u\n", header.dac3.dac_test); + printf("\t dac_disc_H: %u\n", header.dac3.dac_disc_H); + printf("\t delay: %u\n", header.dac3.delay); + printf("\t TP_buff_in: %u\n", header.dac3.TP_buff_in); + printf("\t TP_buff_out: %u\n", header.dac3.TP_buff_out); + printf("\t RPZ: %u\n", header.dac3.RPZ); + printf("\t GND: %u\n", header.dac3.GND); + printf("\t TP_ref: %u\n", header.dac3.TP_ref); + printf("\t FBK: %u\n", header.dac3.FBK); + printf("\t Cas: %u\n", header.dac3.Cas); + printf("\t TP_ref_A: %u\n", header.dac3.TP_ref_A); + printf("\t TP_ref_B: %u\n", header.dac3.TP_ref_B); + printf("header extension id: %4s\n", header.header_extension_id); + printf("extended time stamp: %28s\n", header.extended_timestamp); + printf("exposure time (ns): %u\n", header.exposure_time_ns); + printf("pixel bit depth: %u\n", header.bit_depth); +} diff --git a/src/mq1_single.c b/src/mq1_single.c new file mode 100644 index 0000000..3bfb80f --- /dev/null +++ b/src/mq1_single.c @@ -0,0 +1,120 @@ +#include "mq1_single.h" +#include "mib_header_MQ1.h" +#include "mib_macros.h" +#include "mib_utils.h" +#include +#include +#include + +/* this assumes the provided header is valid + * the header struct will be overwritten + */ +void parse_mq1_single(const char *header, mq1s *mq1_single) +{ + + int n = sscanf( + header, + "%[^,],%u,%u,%u,%u,%u,%[^,],%[^,],%[^,],%[^,]," + "%lf,%u,%u,%u,%f,%f,%f,%f,%f,%f,%f,%f," + "%[^,],%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%" + "u,%u,%u,%u,%u," + "%[^,],%[^,],%uns,%u", + mq1_single->header_id, &mq1_single->sequence_number, + &mq1_single->header_bytes, &mq1_single->num_chips, &mq1_single->det_x, + &mq1_single->det_y, mq1_single->pixel_depth, mq1_single->sensor_layout, + mq1_single->chip_select, mq1_single->timestamp, + &mq1_single->exposure_time_s, &mq1_single->counter, + &mq1_single->colour_mode, &mq1_single->gain_mode, &mq1_single->threshold[0], + &mq1_single->threshold[1], &mq1_single->threshold[2], + &mq1_single->threshold[3], &mq1_single->threshold[4], + &mq1_single->threshold[5], &mq1_single->threshold[6], + &mq1_single->threshold[7], mq1_single->dac0.dac_format, + &mq1_single->dac0.threshold0, &mq1_single->dac0.threshold1, + &mq1_single->dac0.threshold2, &mq1_single->dac0.threshold3, + &mq1_single->dac0.threshold4, &mq1_single->dac0.threshold5, + &mq1_single->dac0.threshold6, &mq1_single->dac0.threshold7, + &mq1_single->dac0.preamp, &mq1_single->dac0.ikrum, &mq1_single->dac0.shaper, + &mq1_single->dac0.disc, &mq1_single->dac0.disc_LS, + &mq1_single->dac0.shaper_test, &mq1_single->dac0.dac_disc_L, + &mq1_single->dac0.dac_test, &mq1_single->dac0.dac_disc_H, + &mq1_single->dac0.delay, &mq1_single->dac0.TP_buff_in, + &mq1_single->dac0.TP_buff_out, &mq1_single->dac0.RPZ, &mq1_single->dac0.GND, + &mq1_single->dac0.TP_ref, &mq1_single->dac0.FBK, &mq1_single->dac0.Cas, + &mq1_single->dac0.TP_ref_A, &mq1_single->dac0.TP_ref_B, + mq1_single->header_extension_id, mq1_single->extended_timestamp, + &mq1_single->exposure_time_ns, &mq1_single->bit_depth); + + if (n == EOF) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: the header appears to be empty\n", + current_file, __LINE__); + exit(1); + } else if (n != MQ1_SINGLE_HEADER_NUM_FIELDS) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: failed to match the MQ1 Quad header\n", + current_file, __LINE__); + exit(1); + } +} + +void print_single_mib_header(mq1s header) +{ + /* Assume the MQ1 Single header (mq1s) has been initialised, + * otherwise you should treat the printed values as garbages. + */ + printf("header id: %3s\n", header.header_id); + printf("sequence number: %u\n", header.sequence_number); + printf("header bytes: %u\n", header.header_bytes); + printf("number of chip(s): %u\n", header.num_chips); + printf("detector size in x: %u\n", header.det_x); + printf("detector size in y: %u\n", header.det_y); + printf("pixel data type: %3s\n", header.pixel_depth); + printf("sensor layout: %6s\n", header.sensor_layout); + printf("chip selected: %2s\n", header.chip_select); + printf("time stamp: %26s\n", header.timestamp); + printf("exposure time (s): %lf\n", header.exposure_time_s); + printf("counter: %u\n", header.counter); + printf("colour mode: %u\n", header.colour_mode); + printf("gain mode: %u\n", header.gain_mode); + printf("threshold 0: %f keV\n", header.threshold[0]); + printf("threshold 1: %f keV\n", header.threshold[1]); + printf("threshold 2: %f keV\n", header.threshold[2]); + printf("threshold 3: %f keV\n", header.threshold[3]); + printf("threshold 4: %f keV\n", header.threshold[4]); + printf("threshold 5: %f keV\n", header.threshold[5]); + printf("threshold 6: %f keV\n", header.threshold[6]); + printf("threshold 7: %f keV\n", header.threshold[7]); + puts("DAC 0:"); + printf("\t DAC format: %3s\n", header.dac0.dac_format); + printf("\t threshold0: %u\n", header.dac0.threshold0); + printf("\t threshold1: %u\n", header.dac0.threshold1); + printf("\t threshold2: %u\n", header.dac0.threshold2); + printf("\t threshold3: %u\n", header.dac0.threshold3); + printf("\t threshold4: %u\n", header.dac0.threshold4); + printf("\t threshold5: %u\n", header.dac0.threshold5); + printf("\t threshold6: %u\n", header.dac0.threshold6); + printf("\t threshold7: %u\n", header.dac0.threshold7); + printf("\t preamp: %u\n", header.dac0.preamp); + printf("\t ikrum: %u\n", header.dac0.ikrum); + printf("\t shaper: %u\n", header.dac0.shaper); + printf("\t disc: %u\n", header.dac0.disc); + printf("\t disc_LS: %u\n", header.dac0.disc_LS); + printf("\t shaper_test: %u\n", header.dac0.shaper_test); + printf("\t dac_disc_L: %u\n", header.dac0.dac_disc_L); + printf("\t dac_test: %u\n", header.dac0.dac_test); + printf("\t dac_disc_H: %u\n", header.dac0.dac_disc_H); + printf("\t delay: %u\n", header.dac0.delay); + printf("\t TP_buff_in: %u\n", header.dac0.TP_buff_in); + printf("\t TP_buff_out: %u\n", header.dac0.TP_buff_out); + printf("\t RPZ: %u\n", header.dac0.RPZ); + printf("\t GND: %u\n", header.dac0.GND); + printf("\t TP_ref: %u\n", header.dac0.TP_ref); + printf("\t FBK: %u\n", header.dac0.FBK); + printf("\t Cas: %u\n", header.dac0.Cas); + printf("\t TP_ref_A: %u\n", header.dac0.TP_ref_A); + printf("\t TP_ref_B: %u\n", header.dac0.TP_ref_B); + printf("header extension id: %4s\n", header.header_extension_id); + printf("extended time stamp: %28s\n", header.extended_timestamp); + printf("exposure time (ns): %u\n", header.exposure_time_ns); + printf("pixel bit depth: %u\n", header.bit_depth); +} diff --git a/src/read_mq1_headers.c b/src/read_mq1_headers.c new file mode 100644 index 0000000..dfac365 --- /dev/null +++ b/src/read_mq1_headers.c @@ -0,0 +1,395 @@ +#include "read_mq1_headers.h" +#include "mib_header_MQ1.h" +#include "mib_macros.h" +#include "mib_utils.h" +#include "mq1_quad.h" +#include "mq1_single.h" + +#include +#include +#include +#include + +unsigned int mq1_single_from_file(FILE *mib_ptr, + unsigned int nheaders, + unsigned int detector_frame_bytes, + mq1s *mq1s_h, + MQ1_fields *mq1_fields) +{ + unsigned int num_parsed = 0; + char header_buffer[MQ1_SINGLE_HEADER_BYTES + 1] = {0}; + + for (unsigned int i = 0; i < nheaders; ++i) { + /*at the current file position, read the size of a header and save in a + * buffer*/ + if (fgets(header_buffer, sizeof(header_buffer), mib_ptr) == NULL) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, + "%s:%d: error: failed to read the header (%u) of the " + "MIB file into a buffer\n", + current_file, __LINE__, i); + return 0; + } + + /*parse the buffer and assign to the fields of a header struct*/ + parse_mq1_single(header_buffer, &mq1s_h[i]); + + /*upon completion, increased the count of parsed header*/ + num_parsed += 1; + + /*update the corresponding field array*/ + fill_MQ1_single_fields(mq1_fields, i, mq1s_h[i]); + + /*move the file by the size of the detector*/ + /*i.e. point to the next header*/ + fseek(mib_ptr, (long int) detector_frame_bytes, SEEK_CUR); + } + + /*go to the beginning after parsing*/ + if (fseek(mib_ptr, 0, SEEK_SET) != 0) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, + "%s:%d: error: failed to seek to the beginning of the " + "MIB file\n", + current_file, __LINE__); + num_parsed = 0; + } + + return num_parsed; +} + +unsigned int mq1_quad_from_file(FILE *mib_ptr, + unsigned int nheaders, + unsigned int detector_frame_bytes, + mq1q *mq1q_h, + MQ1_fields *mq1_fields) +{ + unsigned int num_parsed = 0; + char header_buffer[MQ1_QUAD_HEADER_BYTES + 1] = {0}; + + for (unsigned int i = 0; i < nheaders; ++i) { + /*at the current file position, read the size of a header and save in a + * buffer*/ + if (fgets(header_buffer, sizeof(header_buffer), mib_ptr) == NULL) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, + "%s:%d: error: failed to read the header (%u) of the " + "MIB file into a buffer\n", + current_file, __LINE__, i); + return 0; + } + + /*parse the buffer and assign to the fields of a header struct*/ + parse_mq1_quad(header_buffer, &mq1q_h[i]); + + /*upon completion, increased the count of parsed header*/ + num_parsed += 1; + + /*update the corresponding field array*/ + fill_MQ1_quad_fields(mq1_fields, i, mq1q_h[i]); + + /*move the file by the size of the detector*/ + /*i.e. point to the next header*/ + fseek(mib_ptr, (long int) detector_frame_bytes, SEEK_CUR); + } + + /*go to the beginning after parsing*/ + if (fseek(mib_ptr, 0, SEEK_SET) != 0) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, + "%s:%d: error: failed to seek to the beginning of the " + "MIB file\n", + current_file, __LINE__); + num_parsed = 0; + } + + return num_parsed; +} + +/* ensure consistent memory allocation for all fields + * use deallocate_MQ1_fields to free all the allocated memory here + * */ +MQ1_fields allocate_MQ1_fields(unsigned int nheaders) +{ + MQ1_fields mq1_fields; + + mq1_fields.max_length = nheaders; + + mq1_fields.sequence_number = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.sequence_number == NULL) { + perror("Memory allocation error for sequence number"); + exit(1); + } + + mq1_fields.header_bytes = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.header_bytes == NULL) { + perror("Memory allocation error for header bytes"); + exit(1); + } + + mq1_fields.num_chips = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.num_chips == NULL) { + perror("Memory allocation error for num chips"); + exit(1); + } + + mq1_fields.det_x = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.det_x == NULL) { + perror("Memory allocation error for det x"); + exit(1); + } + + mq1_fields.det_y = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.det_y == NULL) { + perror("Memory allocation error for det y"); + exit(1); + } + + /*pixel_depth is char[4]*/ + mq1_fields.pixel_depth = (char *) malloc( + sizeof(char) * MQ1_CHAR_LEN_PIXEL_DEPTH * mq1_fields.max_length); + if (mq1_fields.pixel_depth == NULL) { + perror("Memory allocation error for pixel depth"); + exit(1); + } + + /*sensor_layout is char[7]*/ + mq1_fields.sensor_layout = (char *) malloc( + sizeof(char) * MQ1_CHAR_LEN_SENSOR_LAYOUT * mq1_fields.max_length); + if (mq1_fields.sensor_layout == NULL) { + perror("Memory allocation error for sensor layout"); + exit(1); + } + + /*chip_select is char[3]*/ + mq1_fields.chip_select = (char *) malloc( + sizeof(char) * MQ1_CHAR_LEN_CHIP_SELECT * mq1_fields.max_length); + if (mq1_fields.chip_select == NULL) { + perror("Memory allocation error for chip select"); + exit(1); + } + + /*timestamp is char[27]*/ + mq1_fields.timestamp = (char *) malloc(sizeof(char) * MQ1_CHAR_LEN_TIMESTAMP * + mq1_fields.max_length); + if (mq1_fields.timestamp == NULL) { + perror("Memory allocation error for timestamp"); + exit(1); + } + + mq1_fields.exposure_time_s = + (double *) malloc(sizeof(double) * mq1_fields.max_length); + if (mq1_fields.exposure_time_s == NULL) { + perror("Memory allocation error for exposure time s"); + exit(1); + } + + mq1_fields.counter = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.counter == NULL) { + perror("Memory allocation error for counter"); + exit(1); + } + + mq1_fields.colour_mode = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.colour_mode == NULL) { + perror("Memory allocation error for colour mode"); + exit(1); + } + + mq1_fields.gain_mode = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.gain_mode == NULL) { + perror("Memory allocation error for gain mode"); + exit(1); + } + + /*threshold is float[8]*/ + mq1_fields.threshold = (float *) malloc( + sizeof(float) * MQ1_FLOAT_LEN_THRESHOLD * mq1_fields.max_length); + if (mq1_fields.threshold == NULL) { + perror("Memory allocation error for threshold"); + exit(1); + } + + /*header_extension_id is char[5]*/ + mq1_fields.header_extension_id = (char *) malloc( + sizeof(char) * MQ1_CHAR_LEN_HEADER_EXTENSION_ID * mq1_fields.max_length); + if (mq1_fields.header_extension_id == NULL) { + perror("Memory allocation error for header extension id"); + exit(1); + } + + /*header_extension_id is char[31]*/ + mq1_fields.extended_timestamp = (char *) malloc( + sizeof(char) * MQ1_CHAR_LEN_EXTENDED_TIMESTAMP * mq1_fields.max_length); + if (mq1_fields.extended_timestamp == NULL) { + perror("Memory allocation error for extended timestamp"); + exit(1); + } + + mq1_fields.exposure_time_ns = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.exposure_time_ns == NULL) { + perror("Memory allocation error for exposure time ns"); + exit(1); + } + + mq1_fields.bit_depth = + (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); + if (mq1_fields.bit_depth == NULL) { + perror("Memory allocation error for bit depth"); + exit(1); + } + + return mq1_fields; +} + +/* ensure all allocated memory is free */ +void deallocate_MQ1_fields(MQ1_fields mq1_fields) +{ + free(mq1_fields.sequence_number); + mq1_fields.sequence_number = NULL; + free(mq1_fields.header_bytes); + mq1_fields.header_bytes = NULL; + free(mq1_fields.num_chips); + mq1_fields.num_chips = NULL; + free(mq1_fields.det_x); + mq1_fields.det_x = NULL; + free(mq1_fields.det_y); + mq1_fields.det_y = NULL; + free(mq1_fields.pixel_depth); + mq1_fields.pixel_depth = NULL; + free(mq1_fields.sensor_layout); + mq1_fields.sensor_layout = NULL; + free(mq1_fields.chip_select); + mq1_fields.chip_select = NULL; + free(mq1_fields.timestamp); + mq1_fields.timestamp = NULL; + free(mq1_fields.exposure_time_s); + mq1_fields.exposure_time_s = NULL; + free(mq1_fields.counter); + mq1_fields.counter = NULL; + free(mq1_fields.colour_mode); + mq1_fields.colour_mode = NULL; + free(mq1_fields.gain_mode); + mq1_fields.gain_mode = NULL; + free(mq1_fields.threshold); + mq1_fields.threshold = NULL; + free(mq1_fields.header_extension_id); + mq1_fields.header_extension_id = NULL; + free(mq1_fields.extended_timestamp); + mq1_fields.extended_timestamp = NULL; + free(mq1_fields.exposure_time_ns); + mq1_fields.exposure_time_ns = NULL; + free(mq1_fields.bit_depth); + mq1_fields.bit_depth = NULL; +} + +/*for MQ1 single, basically a copy of MQ1 quad*/ +void fill_MQ1_single_fields(MQ1_fields *mq1_field, + unsigned int index, + mq1s mq1_h) +{ + if (index >= mq1_field->max_length) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, + "%s:%d: error: the index of the field is larger than " + "the maximum number of the fields\n", + current_file, __LINE__); + exit(1); + } + + mq1_field->sequence_number[index] = mq1_h.sequence_number; + mq1_field->header_bytes[index] = mq1_h.header_bytes; + mq1_field->num_chips[index] = mq1_h.num_chips; + mq1_field->det_x[index] = mq1_h.det_x; + mq1_field->det_y[index] = mq1_h.det_y; + /*pixel_depth is char[4]*/ + snprintf(mq1_field->pixel_depth + index * MQ1_CHAR_LEN_PIXEL_DEPTH, + MQ1_CHAR_LEN_PIXEL_DEPTH, "%s", mq1_h.pixel_depth); + /*sensor_layout is char[7]*/ + snprintf(mq1_field->sensor_layout + index * MQ1_CHAR_LEN_SENSOR_LAYOUT, + MQ1_CHAR_LEN_SENSOR_LAYOUT, "%s", mq1_h.sensor_layout); + /*chip_select is char[3]*/ + snprintf(mq1_field->chip_select + index * MQ1_CHAR_LEN_CHIP_SELECT, + MQ1_CHAR_LEN_CHIP_SELECT, "%s", mq1_h.chip_select); + /*timestamp is char[27]*/ + snprintf(mq1_field->timestamp + index * MQ1_CHAR_LEN_TIMESTAMP, + MQ1_CHAR_LEN_TIMESTAMP, "%s", mq1_h.timestamp); + mq1_field->exposure_time_s[index] = mq1_h.exposure_time_s; + mq1_field->counter[index] = mq1_h.counter; + mq1_field->colour_mode[index] = mq1_h.colour_mode; + mq1_field->gain_mode[index] = mq1_h.gain_mode; + /*threshold is float[8]*/ + for (unsigned int i = 0; i < MQ1_FLOAT_LEN_THRESHOLD; ++i) { + mq1_field->threshold[index * MQ1_FLOAT_LEN_THRESHOLD + i] = + mq1_h.threshold[i]; + } + /*header_extension_id is char[5]*/ + snprintf(mq1_field->header_extension_id + + index * MQ1_CHAR_LEN_HEADER_EXTENSION_ID, + MQ1_CHAR_LEN_HEADER_EXTENSION_ID, "%s", mq1_h.header_extension_id); + /*extended_timestamp is char[31]*/ + snprintf(mq1_field->extended_timestamp + + index * MQ1_CHAR_LEN_EXTENDED_TIMESTAMP, + MQ1_CHAR_LEN_EXTENDED_TIMESTAMP, "%s", mq1_h.extended_timestamp); + mq1_field->exposure_time_ns[index] = mq1_h.exposure_time_ns; + mq1_field->bit_depth[index] = mq1_h.bit_depth; +} + +/*for MQ1 quad, basically a copy of MQ1 single*/ +void fill_MQ1_quad_fields(MQ1_fields *mq1_field, unsigned int index, mq1q mq1_h) +{ + if (index >= mq1_field->max_length) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, + "%s:%d: error: the index of the field is larger than " + "the maximum number of the fields\n", + current_file, __LINE__); + exit(1); + } + + mq1_field->sequence_number[index] = mq1_h.sequence_number; + mq1_field->header_bytes[index] = mq1_h.header_bytes; + mq1_field->num_chips[index] = mq1_h.num_chips; + mq1_field->det_x[index] = mq1_h.det_x; + mq1_field->det_y[index] = mq1_h.det_y; + /*pixel_depth is char[4]*/ + snprintf(mq1_field->pixel_depth + index * MQ1_CHAR_LEN_PIXEL_DEPTH, + MQ1_CHAR_LEN_PIXEL_DEPTH, "%s", mq1_h.pixel_depth); + /*sensor_layout is char[7]*/ + snprintf(mq1_field->sensor_layout + index * MQ1_CHAR_LEN_SENSOR_LAYOUT, + MQ1_CHAR_LEN_SENSOR_LAYOUT, "%s", mq1_h.sensor_layout); + /*chip_select is char[3]*/ + snprintf(mq1_field->chip_select + index * MQ1_CHAR_LEN_CHIP_SELECT, + MQ1_CHAR_LEN_CHIP_SELECT, "%s", mq1_h.chip_select); + /*timestamp is char[27]*/ + snprintf(mq1_field->timestamp + index * MQ1_CHAR_LEN_TIMESTAMP, + MQ1_CHAR_LEN_TIMESTAMP, "%s", mq1_h.timestamp); + mq1_field->exposure_time_s[index] = mq1_h.exposure_time_s; + mq1_field->counter[index] = mq1_h.counter; + mq1_field->colour_mode[index] = mq1_h.colour_mode; + mq1_field->gain_mode[index] = mq1_h.gain_mode; + /*threshold is float[8]*/ + for (unsigned int i = 0; i < MQ1_FLOAT_LEN_THRESHOLD; ++i) { + mq1_field->threshold[index * MQ1_FLOAT_LEN_THRESHOLD + i] = + mq1_h.threshold[i]; + } + /*header_extension_id is char[5]*/ + snprintf(mq1_field->header_extension_id + + index * MQ1_CHAR_LEN_HEADER_EXTENSION_ID, + MQ1_CHAR_LEN_HEADER_EXTENSION_ID, "%s", mq1_h.header_extension_id); + /*extended_timestamp is char[31]*/ + snprintf(mq1_field->extended_timestamp + + index * MQ1_CHAR_LEN_EXTENDED_TIMESTAMP, + MQ1_CHAR_LEN_EXTENDED_TIMESTAMP, "%s", mq1_h.extended_timestamp); + mq1_field->exposure_time_ns[index] = mq1_h.exposure_time_ns; + mq1_field->bit_depth[index] = mq1_h.bit_depth; +} From 5ab4325828f06aec0cdad242cb426489cfe174d2 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 7 Apr 2025 14:58:48 +0100 Subject: [PATCH 002/251] rm main.c for clarity --- src/main.c | 221 ----------------------------------------------------- 1 file changed, 221 deletions(-) delete mode 100644 src/main.c diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 0c6ca62..0000000 --- a/src/main.c +++ /dev/null @@ -1,221 +0,0 @@ -#include "append.h" -#include "framebuffer.h" -#include "hdf5_init.h" -#include "hdf5_init_meta.h" -#include "mib_header_DAC.h" -#include "mib_header_MQ1.h" -#include "mib_macros.h" -#include "mib_props_supp.h" -#include "mib_utils.h" -#include "mq1_quad.h" -#include "mq1_single.h" -#include "read.h" -#include "read_mq1_headers.h" -#include -#include -#include -#include - -// Declaration of Marco here, temporary - -#define MERLIN_DSET_NAME "MerlinData" -#define COMPRESSION_LEVEL 9 -#define DIM 3 -#define NUM_META_FIELD 19 -#define NUM_DAC_FIELD 28 - -int main(int argc, char *argv[]) -{ - // === start get and check arguments === - clock_t begin_total = clock(); - - /* Now this can only handle one .mib file - * TO-DO(near future): add checks to see if more files have been provided as - * argument. TO-DO(further): handle multiple files - */ - if (argc < 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; - } - - /* Cut out the filename from $(filename).mib for the filename of hdf5 - * The output hdf5 file should have the same filename as the .mib - * i.e. example.mib -> example.hdf5 - */ - const char *filename = argv[1]; - const char *base = strrchr(filename, '/'); - base = base ? base + 1 : filename; - - char hdf5_filename[512]; - strncpy(hdf5_filename, base, sizeof(hdf5_filename) - 1); - hdf5_filename[sizeof(hdf5_filename) - 1] = '\0'; - - char *dot = strrchr(hdf5_filename, '.'); - if (dot) - *dot = '\0'; - - size_t len = strlen(hdf5_filename); - if (len + strlen(".hdf5") < sizeof(hdf5_filename)) { - strcat(hdf5_filename, ".hdf5"); - } else { - fprintf(stderr, "Filename buffer too small to append .hdf5\n"); - } - - FILE *mib_ptr = fopen(filename, "rb"); - if (!mib_ptr) { - perror("Failed to open .mib file"); - return 1; - } - - // === end === - - printf("+++ get and check argument done +++\n\n"); - - // === start declaring variables and get metadata for the .mib file === - - clock_t begin = clock(); - - /* Please check the struct framebuffer from the header files in /include - */ - - framebuffer frame; - framebuffer *frame_ptr = &frame; - long ptr_pos = ftell(mib_ptr); - // printf("pointer starting position: %ld\n", ptr_pos); - - char *header_id = malloc(4 * sizeof(char)); - unsigned int *header_bytes = malloc(5 * sizeof(unsigned int)); - unsigned int *num_chips = malloc(sizeof(unsigned int)); - unsigned int *det_x = malloc(4 * sizeof(unsigned int)); - unsigned int *det_y = malloc(4 * sizeof(unsigned int)); - char *pixel_depth = malloc(4 * sizeof(char)); - - header_meta_from_first(mib_ptr, header_id, header_bytes, num_chips, det_x, - det_y, pixel_depth); - int bufsize = (pixel_depth[1] - '0') * 10 + (pixel_depth[2] - '0'); - bufsize = bufsize / 8; - - // === end === - - printf("+++ declaring variables done +++\n\n"); - clock_t end = clock(); - double time_get_header_meta_from_first = - (double) (end - begin) / CLOCKS_PER_SEC; - printf("+++ Time to get header meta data: %02f +++\n", - time_get_header_meta_from_first); - - // === start initialize hdf5 === - - begin = clock(); - - /* Declare variables related to creating hdf5 files - * Please check the functions in hdf5_init.c and hdf5_meta_init.c - * Handles are arrays that stored dataset ids for different metadata - */ - - hid_t file_id, fapl_id, fcpl_id, lcpl_id; - initialize_file_and_plist(hdf5_filename, &file_id, &fapl_id, &fcpl_id); - initialize_lcpl(&lcpl_id); - - hid_t frame_dset_id; - hsize_t dim[DIM] = {0, *det_y, *det_x}; - hsize_t max_dim[DIM] = {H5S_UNLIMITED, *det_y, *det_x}; - hsize_t frame_dim[DIM] = {1, *det_y, *det_x}; - - hid_t memspace = H5Screate_simple(DIM, dim, max_dim); - if (memspace == H5I_INVALID_HID) { - fprintf(stderr, "Error in creating memspace in main\n"); - return 1; - } - // printf("=== create frame dataset ===\n"); - create_merlin_dataset(&frame_dset_id, &file_id, MERLIN_DSET_NAME, bufsize, - memspace, &lcpl_id, DIM, frame_dim, COMPRESSION_LEVEL); - // printf("=== done create frame dataset ===\n"); - - hid_t meta_handle[NUM_META_FIELD]; - hid_t dac_handle[NUM_DAC_FIELD * 4]; - - create_meta_mq1_fields_dataset(&file_id, &lcpl_id, meta_handle); - // printf("== done create meta_mq1===\n"); - create_dac_dataset(*num_chips, &file_id, &lcpl_id, dac_handle); - - // === end initialize hdf5 === - - // printf("+++ init hdf5 done +++\n"); - end = clock(); - double time_initialize_hdf5 = (double) (end - begin) / CLOCKS_PER_SEC; - printf("+++ Time to init hdf5: %02f +++\n", time_initialize_hdf5); - - // === start appending === - begin = clock(); - /* Check if it is EOF each time - * Please check the functions in read.c and append.c - */ - - int c = 0; - int loop = 0; - size_t num_meta, num_dac; - while ((c = fgetc(mib_ptr)) != EOF) { - ungetc(c, mib_ptr); - ptr_pos = ftell(mib_ptr); - - // printf("loop %d: read .mib\n", loop); - - read_header(mib_ptr, ptr_pos, frame_ptr); - read_frame(mib_ptr, ptr_pos, frame_ptr); - - // printf("\n\nChip0 GND: %u\n\n", frame_ptr->dac0->GND); - // printf("\n\nChip0 FBK: %u\n\n", frame_ptr->dac0->FBK); - - // printf("loop %d: read .mib end\n", loop); - - // printf("loop %d: append meta\n", loop); - - append_meta_to_dataset(&file_id, &num_meta, meta_handle, frame_ptr); - - // printf("loop %d: append meta end\n", loop); - - // printf("loop %d: append dac\n", loop); - - append_dac_to_dataset(&file_id, &num_dac, *num_chips, dac_handle, - frame_ptr); - - // printf("loop %d: append dac end\n", loop); - - // printf("loop %d: append frame\n", loop); - - append_frame_to_dataset(&file_id, &frame_dset_id, frame_ptr); - - // printf("loop %d: append frame end\n", loop); - - deallocate_MQ1_fields(*(frame.mq1_header)); - // printf("deallocate_MQ1_fields\n"); - free(frame.mq1_header); - // printf("free frame.mq1_header\n"); - frame.mq1_header = NULL; - // printf("NULL frame.mq1_header\n"); - free_frame(frame_ptr); - // printf("free_frame\n"); - - // printf("pointer position after loop %d: %ld\n", loop, ftell(mib_ptr)); - loop++; - } - - // === end appending === - end = clock(); - double time_total_loop = (double) (end - begin) / CLOCKS_PER_SEC; - double time_per_loop = time_total_loop / loop; - printf("+++ Time per loop: %02f +++\n", time_per_loop); - - H5Pclose(fapl_id); - H5Pclose(fcpl_id); - H5Pclose(lcpl_id); - H5Fflush(file_id, H5F_SCOPE_GLOBAL); - H5Fclose(file_id); - fclose(mib_ptr); - - clock_t end_total = clock(); - double time_total = (double) (end_total - begin_total) / CLOCKS_PER_SEC; - printf("+++ total time usage: %02f +++\n", time_total); - return 0; -} From 220402b58648f1a786582d743d14a133e181a977 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 4 Apr 2025 11:30:52 +0100 Subject: [PATCH 003/251] Add clang-format configuration file --- .clang-format | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..6781738 --- /dev/null +++ b/.clang-format @@ -0,0 +1,25 @@ +BasedOnStyle: LLVM +Language: C +IndentWidth: 2 +ContinuationIndentWidth: 2 +ColumnLimit: 80 +PointerAlignment: Right +BreakBeforeBraces: Linux +UseTab: Never +MaxEmptyLinesToKeep: 1 +SpaceBeforeParens: ControlStatements +AllowShortIfStatementsOnASingleLine: Never +IndentCaseLabels: true +SortIncludes: CaseInsensitive +IncludeBlocks: Preserve +SpaceAfterCStyleCast: true +AlignConsecutiveAssignments: Consecutive +AllowShortFunctionsOnASingleLine: None +AllowShortBlocksOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +BinPackParameters: OnePerLine +AlignAfterOpenBracket: Align +SpaceBeforeAssignmentOperators: true +AlignTrailingComments: + Kind: Always + OverEmptyLines: 1 From 274a73136fdff381b909c72e86e9bf22066b8068 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 4 Apr 2025 11:31:30 +0100 Subject: [PATCH 004/251] Add GitHub Action to check formatting by clang-format --- .github/workflows/clang-format-check.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/clang-format-check.yml diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml new file mode 100644 index 0000000..0eb8971 --- /dev/null +++ b/.github/workflows/clang-format-check.yml @@ -0,0 +1,20 @@ +name: clang-format Check + +on: + push: + branches: + - main + - dev + pull_request: + +jobs: + formatting-check: + runs-on: ubuntu-latest + name: Formatting Check + steps: + - uses: actions/checkout@v4 + - name: Run clang-format style check + uses: jidicula/clang-format-action@v4.15.0 + with: + clang-format-version: '20' + check-path: 'src' From 9f5af3b5f2bbc2586e8d5a0af5f1044f4bc4da3f Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 4 Apr 2025 11:56:12 +0100 Subject: [PATCH 005/251] Add basic pre-commit hooks --- .pre-commit-config.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9607893 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-merge-conflict + - id: check-symlinks + - id: end-of-file-fixer + - id: mixed-line-ending + - id: trailing-whitespace From c83c74a5cbc14b731448a5c87a6d532fe33edad6 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 4 Apr 2025 11:56:46 +0100 Subject: [PATCH 006/251] Add hook to lint markdown --- .pre-commit-config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9607893..a589d1c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,3 +9,8 @@ repos: - id: end-of-file-fixer - id: mixed-line-ending - id: trailing-whitespace + + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.44.0 + hooks: + - id: markdownlint From db2d0448d9638eb6ac83b2cca6b844267346fb53 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 4 Apr 2025 11:57:07 +0100 Subject: [PATCH 007/251] Add hook to use clang-format --- .pre-commit-config.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a589d1c..aa0d63c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,3 +14,9 @@ repos: rev: v0.44.0 hooks: - id: markdownlint + + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v20.1.0 + hooks: + - id: clang-format + types_or: [c] From e48498ec0252c845f2b085b3cdc86d8f9ec6ccb8 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 8 Apr 2025 09:06:31 +0100 Subject: [PATCH 008/251] Changes in config.mk to add different build targets, emit error message when no HDF5_ROOT path --- config.mk | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/config.mk b/config.mk index 43b1c82..d2b5a00 100644 --- a/config.mk +++ b/config.mk @@ -1,20 +1,37 @@ # === Directories === SRCDIR := src OBJDIR := obj -BINDIR := bin +BINDIR ?= bin INCDIR := include -HDFDIR := $(HDF5_ROOT) +HDFDIR ?= $(HDF5_ROOT) + +BUILD ?= debug + +ifndef HDFDIR +$(error HDFDIR is not defined. Please set HDF5_ROOT or pass HDFDIR=...) +endif # === Compiler and flags === CC := gcc -CFLAGS := -Wall -Wextra -std=c11 -g -O0 -fanalyzer -I$(SRCDIR) -I$(INCDIR) -I$(HDFDIR)/include -LDFLAGS := -L$(HDFDIR)/lib -lhdf5 + +ifeq ($(BUILD),debug) + CFLAGS := -Wall -Wextra -std=c11 -g -O0 -fanalyzer +else ifeq ($(BUILD),release) + CFLAGS := -Wall -Wextra -std=c11 -O2 +else ifeq ($(BUILD),asan) + CFLAGS := -Wall -Wextra -std=c11 -g -O0 -fsanitize=address + LDFLAGS += -fsanitize=address +else + $(error Unknown BUILD type: $(BUILD)) +endif + +CFLAGS += -I$(SRCDIR) -I$(INCDIR) -I$(HDFDIR)/include +LDFLAGS += -L$(HDFDIR)/lib -lhdf5 # === Sources === SOURCES := $(wildcard $(SRCDIR)/*.c) -OBJECTS := \ - $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SOURCES)) \ +OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SOURCES)) -TARGET := $(BINDIR)/main.out +TARGET := $(BINDIR)/mib2h5 From 830482b8a737a966689b7d0b4e4597fb0cd335c7 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 8 Apr 2025 14:54:39 +0100 Subject: [PATCH 009/251] Remove empty allocate_frame function --- include/framebuffer.h | 1 - src/framebuffer.c | 5 ----- src/mib_props_supp.c | 3 +++ 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/framebuffer.h b/include/framebuffer.h index dfa1a00..7b26b21 100644 --- a/include/framebuffer.h +++ b/include/framebuffer.h @@ -20,7 +20,6 @@ typedef struct { void *data; } framebuffer; -void allocate_frame(framebuffer* fb); void free_frame(framebuffer* fb); #endif diff --git a/src/framebuffer.c b/src/framebuffer.c index fc965f6..b30f8b4 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -12,11 +12,6 @@ #include #include -void allocate_frame(framebuffer *fb) -{ - return; -} - void free_frame(framebuffer *fb) { if (fb->rows) diff --git a/src/mib_props_supp.c b/src/mib_props_supp.c index 981defd..3eb178a 100644 --- a/src/mib_props_supp.c +++ b/src/mib_props_supp.c @@ -9,6 +9,9 @@ #include #include +/* Mainly this is just for easy access to mq1_fields and dac + */ + info *mq1_fields_iter(MQ1_fields *fields_struct, size_t *out_count) { if (!fields_struct || !out_count) From 93c95c626f42f9aea453141407058b9700d8e9df Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Tue, 8 Apr 2025 16:12:50 +0100 Subject: [PATCH 010/251] Check style of include files in CI --- .github/workflows/clang-format-check.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 0eb8971..026acb7 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -11,10 +11,15 @@ jobs: formatting-check: runs-on: ubuntu-latest name: Formatting Check + strategy: + matrix: + path: + - 'src' + - 'include' steps: - uses: actions/checkout@v4 - name: Run clang-format style check uses: jidicula/clang-format-action@v4.15.0 with: clang-format-version: '20' - check-path: 'src' + check-path: ${{ matrix.path }} From 0ede56066aa561f12960ae59fc2284e97107d752 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 8 Apr 2025 17:15:57 +0100 Subject: [PATCH 011/251] Added clang-format checks to header files in include and performed pre-commit checks --- .gitignore | 1 + Makefile | 1 - bin/mib2h5 | Bin 0 -> 59368 bytes include/framebuffer.h | 21 +++++----- include/mib_header_DAC.h | 1 + include/mib_header_MQ1.h | 2 +- include/mib_macros.h | 1 + include/mib_props_supp.h | 15 ++++---- include/mib_utils.h | 24 +++++------- include/mq1_quad.h | 4 +- include/mq1_single.h | 4 +- include/read_mq1_headers.h | 77 +++++++++++++++++-------------------- 12 files changed, 72 insertions(+), 79 deletions(-) create mode 100755 bin/mib2h5 diff --git a/.gitignore b/.gitignore index 70c4d04..7cce8cb 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ doc/.build/* *egg-info* *__pycache__* *sg_execution_times.rst +venv/* diff --git a/Makefile b/Makefile index 7749412..bd99ecc 100644 --- a/Makefile +++ b/Makefile @@ -18,4 +18,3 @@ $(BINDIR): clean: rm -rf $(OBJDIR)/*.o $(TARGET) - diff --git a/bin/mib2h5 b/bin/mib2h5 new file mode 100755 index 0000000000000000000000000000000000000000..7f2af8a2b04883c2ed7aa4c9ecc31cc97b821b7c GIT binary patch literal 59368 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 ut;GlZw)#=u -#include "mib_header_MQ1.h" #include "mib_header_DAC.h" +#include "mib_header_MQ1.h" #include "mib_macros.h" #include "mib_utils.h" #include "mq1_quad.h" #include "mq1_single.h" #include "read_mq1_headers.h" +#include typedef struct { - MQ1_fields *mq1_header; - dac_rx *dac0; - dac_rx *dac1; - dac_rx *dac2; - dac_rx *dac3; - void **rows; - void *data; + MQ1_fields *mq1_header; + dac_rx *dac0; + dac_rx *dac1; + dac_rx *dac2; + dac_rx *dac3; + void **rows; + void *data; } framebuffer; -void free_frame(framebuffer* fb); +void free_frame(framebuffer *fb); #endif diff --git a/include/mib_header_DAC.h b/include/mib_header_DAC.h index 68f13d2..d8b6141 100644 --- a/include/mib_header_DAC.h +++ b/include/mib_header_DAC.h @@ -1,3 +1,4 @@ +// clang-format Language: C #ifndef MIB_HEADER_DAC_RX_H #define MIB_HEADER_DAC_RX_H diff --git a/include/mib_header_MQ1.h b/include/mib_header_MQ1.h index e28a092..a107de8 100644 --- a/include/mib_header_MQ1.h +++ b/include/mib_header_MQ1.h @@ -1,3 +1,4 @@ +// clang-format Language: C /* field 1: header ID (MQ1) field 2: sequence number of a frame @@ -57,7 +58,6 @@ typedef struct { #endif - #ifndef MIB_HEADER_MQ1_QUAD_H #define MIB_HEADER_MQ1_QUAD_H diff --git a/include/mib_macros.h b/include/mib_macros.h index 19cf76f..c12a846 100644 --- a/include/mib_macros.h +++ b/include/mib_macros.h @@ -1,3 +1,4 @@ +// clang-format Language: C #ifndef MQ1_SINGLE_HEADER_BYTES #define MQ1_SINGLE_HEADER_BYTES 384 #endif diff --git a/include/mib_props_supp.h b/include/mib_props_supp.h index 1155140..f681bf5 100644 --- a/include/mib_props_supp.h +++ b/include/mib_props_supp.h @@ -1,18 +1,19 @@ +// clang-format Language: C #ifndef MQ1_FIELD_ITER_H #define MQ1_FIELD_ITER_H -#include -#include -#include "mib_header_MQ1.h" #include "mib_header_DAC.h" +#include "mib_header_MQ1.h" #include "read_mq1_headers.h" +#include +#include typedef struct { - const char* name; - void* data; + const char *name; + void *data; } info; -info* mq1_fields_iter(MQ1_fields* fields, size_t* out_count); -info* dac_iter(dac_rx* dac, size_t* out_count); +info *mq1_fields_iter(MQ1_fields *fields, size_t *out_count); +info *dac_iter(dac_rx *dac, size_t *out_count); #endif diff --git a/include/mib_utils.h b/include/mib_utils.h index 798de47..eb68b37 100644 --- a/include/mib_utils.h +++ b/include/mib_utils.h @@ -1,27 +1,23 @@ +// clang-format Language: C #include #ifndef ONLY_FILE_NAME_H #define ONLY_FILE_NAME_H -const char* only_file_name(const char* absolute_file_path); +const char *only_file_name(const char *absolute_file_path); #endif /*ONLY_FILE_NAME_H*/ #ifndef NUM_OF_HEADERS_H #define NUM_OF_HEADERS_H -unsigned int num_of_headers( - FILE* mib_ptr, - const unsigned int stride - ); +unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride); #endif #ifndef HEADER_META_FROM_FIRST_H #define HEADER_META_FROM_FIRST_H -void header_meta_from_first( - FILE* mib_ptr, - char* header_id, - unsigned int* header_bytes, - unsigned int* num_chips, - unsigned int* det_x, - unsigned int* det_y, - char* pixel_depth - ); +void header_meta_from_first(FILE *mib_ptr, + char *header_id, + unsigned int *header_bytes, + unsigned int *num_chips, + unsigned int *det_x, + unsigned int *det_y, + char *pixel_depth); #endif diff --git a/include/mq1_quad.h b/include/mq1_quad.h index 907cb1a..2e387d9 100644 --- a/include/mq1_quad.h +++ b/include/mq1_quad.h @@ -1,12 +1,12 @@ +// clang-format Language: C #include "mib_header_MQ1.h" #ifndef PARSE_MQ1_QUAD_H #define PARSE_MQ1_QUAD_H -void parse_mq1_quad(const char* header, mq1q* mq1_quad); +void parse_mq1_quad(const char *header, mq1q *mq1_quad); #endif #ifndef PRINT_QUAD_MIB_HEADER_H #define PRINT_QUAD_MIB_HEADER_H void print_quad_mib_header(mq1q header); #endif - diff --git a/include/mq1_single.h b/include/mq1_single.h index 696c6ed..e054dfd 100644 --- a/include/mq1_single.h +++ b/include/mq1_single.h @@ -1,12 +1,12 @@ +// clang-format Language: C #include "mib_header_MQ1.h" #ifndef PARSE_MQ1_SINGLE_H #define PARSE_MQ1_SINGLE_H -void parse_mq1_single(const char* header, mq1s* mq1_single); +void parse_mq1_single(const char *header, mq1s *mq1_single); #endif #ifndef PRINT_SINGLE_MIB_HEADER_H #define PRINT_SINGLE_MIB_HEADER_H void print_single_mib_header(mq1s header); #endif - diff --git a/include/read_mq1_headers.h b/include/read_mq1_headers.h index 261c449..8235fd4 100644 --- a/include/read_mq1_headers.h +++ b/include/read_mq1_headers.h @@ -1,3 +1,4 @@ +// clang-format Language: C #include #include @@ -6,24 +7,24 @@ typedef struct { unsigned int max_length; - unsigned int* sequence_number; - unsigned int* header_bytes; - unsigned int* num_chips; - unsigned int* det_x; - unsigned int* det_y; - char* pixel_depth; - char* sensor_layout; - char* chip_select; - char* timestamp; - double* exposure_time_s; - unsigned int* counter; - unsigned int* colour_mode; - unsigned int* gain_mode; - float* threshold; - char* header_extension_id; - char* extended_timestamp; - unsigned int* exposure_time_ns; - unsigned int* bit_depth; + unsigned int *sequence_number; + unsigned int *header_bytes; + unsigned int *num_chips; + unsigned int *det_x; + unsigned int *det_y; + char *pixel_depth; + char *sensor_layout; + char *chip_select; + char *timestamp; + double *exposure_time_s; + unsigned int *counter; + unsigned int *colour_mode; + unsigned int *gain_mode; + float *threshold; + char *header_extension_id; + char *extended_timestamp; + unsigned int *exposure_time_ns; + unsigned int *bit_depth; } MQ1_fields; #endif @@ -44,40 +45,32 @@ void deallocate_MQ1_fields(MQ1_fields mq1_fields); #ifndef MQ1_SINGLE_FROM_FILE_H #define MQ1_SINGLE_FROM_FILE_H -unsigned int mq1_single_from_file( - FILE* mib_ptr, - unsigned int nheaders, - unsigned int detector_frame_bytes, - mq1s* mq1s_h, - MQ1_fields* mq1_fields - ); +unsigned int mq1_single_from_file(FILE *mib_ptr, + unsigned int nheaders, + unsigned int detector_frame_bytes, + mq1s *mq1s_h, + MQ1_fields *mq1_fields); #endif #ifndef MQ1_QUAD_FROM_FILE_H #define MQ1_QUAD_FROM_FILE_H -unsigned int mq1_quad_from_file( - FILE* mib_ptr, - unsigned int nheaders, - unsigned int detector_frame_bytes, - mq1q* mq1q_h, - MQ1_fields* mq1_fields - ); +unsigned int mq1_quad_from_file(FILE *mib_ptr, + unsigned int nheaders, + unsigned int detector_frame_bytes, + mq1q *mq1q_h, + MQ1_fields *mq1_fields); #endif #ifndef FILL_MQ1_SINGLE_FIELDS_H #define FILL_MQ1_SINGLE_FIELDS_H -void fill_MQ1_single_fields( - MQ1_fields* mq1_field, - unsigned int index, - mq1s mq1_h - ); +void fill_MQ1_single_fields(MQ1_fields *mq1_field, + unsigned int index, + mq1s mq1_h); #endif #ifndef FILL_MQ1_QUAD_FIELDS_H #define FILL_MQ1_QUAD_FIELDS_H -void fill_MQ1_quad_fields( - MQ1_fields* mq1_field, - unsigned int index, - mq1q mq1_h - ); +void fill_MQ1_quad_fields(MQ1_fields *mq1_field, + unsigned int index, + mq1q mq1_h); #endif From 2c9d69b101167b4f6486f4dcf4bbd310184d960f Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Tue, 8 Apr 2025 17:34:52 +0100 Subject: [PATCH 012/251] Address spacing issue around list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c3a2067..050e3ee 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ mib2h5 -c -d '/rawdata' -r '10x10' -t 300 input.mib ``` This will: + - enable Blosc compression - store the frames at the dataset key `/rawdata` in the HDF5 file - reshape the data to `(10, 10, det_y, det_x)` if there are 100 frames with From 05b4dc43e0a76e6afaa687f160e7a8cbbe4e2e46 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Tue, 8 Apr 2025 17:35:28 +0100 Subject: [PATCH 013/251] Allow duplicated heading with different parents --- .markdownlint.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .markdownlint.yaml diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 0000000..05c6bc3 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,2 @@ +MD024: + siblings_only: true From 1f9ba5f24505807875c53edc095fa431ba302391 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 9 Apr 2025 15:16:18 +0100 Subject: [PATCH 014/251] Make changes based on suggestions, created parser.[ch], io_header.[ch], utils.[ch], mib_header.h --- bin/mib2h5 | Bin 59368 -> 0 bytes include/{read_mq1_headers.h => io_header.h} | 19 ++- include/{mib_header_MQ1.h => mib_header.h} | 38 +++++- include/mib_header_DAC.h | 36 ------ include/mib_props_supp.h | 19 --- include/mq1_quad.h | 12 -- include/{mq1_single.h => parser.h} | 10 ++ include/{mib_utils.h => utils.h} | 0 src/framebuffer.c | 8 +- src/{read_mq1_headers.c => io_header.c} | 99 +++++++++++++++- src/mib_props_supp.c | 98 ---------------- src/mq1_single.c | 120 ------------------- src/{mq1_quad.c => parser.c} | 121 +++++++++++++++++++- src/{mib_utils.c => utils.c} | 2 +- 14 files changed, 277 insertions(+), 305 deletions(-) delete mode 100755 bin/mib2h5 rename include/{read_mq1_headers.h => io_header.h} (84%) rename include/{mib_header_MQ1.h => mib_header.h} (77%) delete mode 100644 include/mib_header_DAC.h delete mode 100644 include/mib_props_supp.h delete mode 100644 include/mq1_quad.h rename include/{mq1_single.h => parser.h} (56%) rename include/{mib_utils.h => utils.h} (100%) rename src/{read_mq1_headers.c => io_header.c} (79%) delete mode 100644 src/mib_props_supp.c delete mode 100644 src/mq1_single.c rename src/{mq1_quad.c => parser.c} (69%) rename src/{mib_utils.c => utils.c} (99%) diff --git a/bin/mib2h5 b/bin/mib2h5 deleted file mode 100755 index 7f2af8a2b04883c2ed7aa4c9ecc31cc97b821b7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59368 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 ut;GlZw)#=u +#include "mib_header_DAC.h" +#include "mib_header_MQ1.h" +#include "read_mq1_headers.h" +#include +#include #include #ifndef MQ1_FIELDS_H @@ -74,3 +78,16 @@ void fill_MQ1_quad_fields(MQ1_fields *mq1_field, unsigned int index, mq1q mq1_h); #endif + +#ifndef MQ1_FIELD_ITER_H +#define MQ1_FIELD_ITER_H + +typedef struct { + const char *name; + void *data; +} info; + +info *mq1_fields_iter(MQ1_fields *fields, size_t *out_count); +info *dac_iter(dac_rx *dac, size_t *out_count); + +#endif diff --git a/include/mib_header_MQ1.h b/include/mib_header.h similarity index 77% rename from include/mib_header_MQ1.h rename to include/mib_header.h index a107de8..928598e 100644 --- a/include/mib_header_MQ1.h +++ b/include/mib_header.h @@ -1,4 +1,40 @@ // clang-format Language: C +#include "mib_macros.h" +#ifndef MIB_HEADER_DAC_RX_H +#define MIB_HEADER_DAC_RX_H + +typedef struct { + char dac_format[4]; + unsigned int threshold0; + unsigned int threshold1; + unsigned int threshold2; + unsigned int threshold3; + unsigned int threshold4; + unsigned int threshold5; + unsigned int threshold6; + unsigned int threshold7; + unsigned int preamp; + unsigned int ikrum; + unsigned int shaper; + unsigned int disc; + unsigned int disc_LS; + unsigned int shaper_test; + unsigned int dac_disc_L; + unsigned int dac_test; + unsigned int dac_disc_H; + unsigned int delay; + unsigned int TP_buff_in; + unsigned int TP_buff_out; + unsigned int RPZ; + unsigned int GND; + unsigned int TP_ref; + unsigned int FBK; + unsigned int Cas; + unsigned int TP_ref_A; + unsigned int TP_ref_B; +} dac_rx; + +#endif /* field 1: header ID (MQ1) field 2: sequence number of a frame @@ -27,8 +63,6 @@ field 54 / 138 : the pixel data bit depth The remainings are null bytes for padding. */ -#include "mib_header_DAC.h" -#include "mib_macros.h" #ifndef MIB_HEADER_MQ1_SINGLE_H #define MIB_HEADER_MQ1_SINGLE_H diff --git a/include/mib_header_DAC.h b/include/mib_header_DAC.h deleted file mode 100644 index d8b6141..0000000 --- a/include/mib_header_DAC.h +++ /dev/null @@ -1,36 +0,0 @@ -// clang-format Language: C -#ifndef MIB_HEADER_DAC_RX_H -#define MIB_HEADER_DAC_RX_H - -typedef struct { - char dac_format[4]; - unsigned int threshold0; - unsigned int threshold1; - unsigned int threshold2; - unsigned int threshold3; - unsigned int threshold4; - unsigned int threshold5; - unsigned int threshold6; - unsigned int threshold7; - unsigned int preamp; - unsigned int ikrum; - unsigned int shaper; - unsigned int disc; - unsigned int disc_LS; - unsigned int shaper_test; - unsigned int dac_disc_L; - unsigned int dac_test; - unsigned int dac_disc_H; - unsigned int delay; - unsigned int TP_buff_in; - unsigned int TP_buff_out; - unsigned int RPZ; - unsigned int GND; - unsigned int TP_ref; - unsigned int FBK; - unsigned int Cas; - unsigned int TP_ref_A; - unsigned int TP_ref_B; -} dac_rx; - -#endif diff --git a/include/mib_props_supp.h b/include/mib_props_supp.h deleted file mode 100644 index f681bf5..0000000 --- a/include/mib_props_supp.h +++ /dev/null @@ -1,19 +0,0 @@ -// clang-format Language: C -#ifndef MQ1_FIELD_ITER_H -#define MQ1_FIELD_ITER_H - -#include "mib_header_DAC.h" -#include "mib_header_MQ1.h" -#include "read_mq1_headers.h" -#include -#include - -typedef struct { - const char *name; - void *data; -} info; - -info *mq1_fields_iter(MQ1_fields *fields, size_t *out_count); -info *dac_iter(dac_rx *dac, size_t *out_count); - -#endif diff --git a/include/mq1_quad.h b/include/mq1_quad.h deleted file mode 100644 index 2e387d9..0000000 --- a/include/mq1_quad.h +++ /dev/null @@ -1,12 +0,0 @@ -// clang-format Language: C -#include "mib_header_MQ1.h" - -#ifndef PARSE_MQ1_QUAD_H -#define PARSE_MQ1_QUAD_H -void parse_mq1_quad(const char *header, mq1q *mq1_quad); -#endif - -#ifndef PRINT_QUAD_MIB_HEADER_H -#define PRINT_QUAD_MIB_HEADER_H -void print_quad_mib_header(mq1q header); -#endif diff --git a/include/mq1_single.h b/include/parser.h similarity index 56% rename from include/mq1_single.h rename to include/parser.h index e054dfd..aa2a5a7 100644 --- a/include/mq1_single.h +++ b/include/parser.h @@ -10,3 +10,13 @@ void parse_mq1_single(const char *header, mq1s *mq1_single); #define PRINT_SINGLE_MIB_HEADER_H void print_single_mib_header(mq1s header); #endif + +#ifndef PARSE_MQ1_QUAD_H +#define PARSE_MQ1_QUAD_H +void parse_mq1_quad(const char *header, mq1q *mq1_quad); +#endif + +#ifndef PRINT_QUAD_MIB_HEADER_H +#define PRINT_QUAD_MIB_HEADER_H +void print_quad_mib_header(mq1q header); +#endif diff --git a/include/mib_utils.h b/include/utils.h similarity index 100% rename from include/mib_utils.h rename to include/utils.h diff --git a/src/framebuffer.c b/src/framebuffer.c index b30f8b4..96bd541 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -1,12 +1,6 @@ #include "framebuffer.h" -#include "mib_header_DAC.h" -#include "mib_header_MQ1.h" #include "mib_macros.h" -#include "mib_props_supp.h" -#include "mib_utils.h" -#include "mq1_quad.h" -#include "mq1_single.h" -#include "read_mq1_headers.h" +#include "utils.h" #include #include #include diff --git a/src/read_mq1_headers.c b/src/io_header.c similarity index 79% rename from src/read_mq1_headers.c rename to src/io_header.c index dfac365..4ad7b3b 100644 --- a/src/read_mq1_headers.c +++ b/src/io_header.c @@ -1,10 +1,9 @@ -#include "read_mq1_headers.h" -#include "mib_header_MQ1.h" +#include "io_header.h" +#include "mib_header.h" #include "mib_macros.h" -#include "mib_utils.h" -#include "mq1_quad.h" -#include "mq1_single.h" - +#include "parser.h" +#include "read_mq1_headers.h" +#include "utils.h" #include #include #include @@ -393,3 +392,91 @@ void fill_MQ1_quad_fields(MQ1_fields *mq1_field, unsigned int index, mq1q mq1_h) mq1_field->exposure_time_ns[index] = mq1_h.exposure_time_ns; mq1_field->bit_depth[index] = mq1_h.bit_depth; } + +/* Mainly this is just for easy access to mq1_fields and dac + */ + +info *mq1_fields_info(MQ1_fields *fields_struct, size_t num_count) +{ + if (!fields_struct || !num_count) + return NULL; + + if (num_count != 19) { + fprintf(stderr, "Wrong number of fields in mq1_fields_info\n"); + return NULL; + } + + info *fields = malloc(num_count * sizeof(info)); + if (!fields) + return NULL; + + fields[0] = (info) {"max_length", &fields_struct->max_length}; + fields[1] = (info) {"sequence_number", fields_struct->sequence_number}; + fields[2] = (info) {"header_bytes", fields_struct->header_bytes}; + fields[3] = (info) {"num_chips", fields_struct->num_chips}; + fields[4] = (info) {"det_x", fields_struct->det_x}; + fields[5] = (info) {"det_y", fields_struct->det_y}; + fields[6] = (info) {"pixel_depth", fields_struct->pixel_depth}; + fields[7] = (info) {"sensor_layout", fields_struct->sensor_layout}; + fields[8] = (info) {"chip_select", fields_struct->chip_select}; + fields[9] = (info) {"timestamp", fields_struct->timestamp}; + fields[10] = (info) {"exposure_time_s", fields_struct->exposure_time_s}; + fields[11] = (info) {"counter", fields_struct->counter}; + fields[12] = (info) {"colour_mode", fields_struct->colour_mode}; + fields[13] = (info) {"gain_mode", fields_struct->gain_mode}; + fields[14] = (info) {"threshold", fields_struct->threshold}; + fields[15] = + (info) {"header_extension_id", fields_struct->header_extension_id}; + fields[16] = (info) {"extended_timestamp", fields_struct->extended_timestamp}; + fields[17] = (info) {"exposure_time_ns", fields_struct->exposure_time_ns}; + fields[18] = (info) {"bit_depth", fields_struct->bit_depth}; + + return fields; +} + +info *dac_info(dac_rx *dac, size_t num_count) +{ + if (!dac || !out_count) + return NULL; + + if (num_count != 28) { + fprintf(stderr, "Wrong number of fields in dac_info\n"); + return NULL; + } + + info *dinfo = malloc(NUM_FIELDS * sizeof(info)); + if (!dinfo) + return NULL; + + dinfo[0] = (info) {"dac_format", &dac->dac_format}; + dinfo[1] = (info) {"threshold0", &dac->threshold0}; + dinfo[2] = (info) {"threshold1", &dac->threshold1}; + dinfo[3] = (info) {"threshold2", &dac->threshold2}; + dinfo[4] = (info) {"threshold3", &dac->threshold3}; + dinfo[5] = (info) {"threshold4", &dac->threshold4}; + dinfo[6] = (info) {"threshold5", &dac->threshold5}; + dinfo[7] = (info) {"threshold6", &dac->threshold6}; + dinfo[8] = (info) {"threshold7", &dac->threshold7}; + dinfo[9] = (info) {"preamp", &dac->preamp}; + dinfo[10] = (info) {"ikrum", &dac->ikrum}; + dinfo[11] = (info) {"shaper", &dac->shaper}; + dinfo[12] = (info) {"disc", &dac->disc}; + dinfo[13] = (info) {"disc_LS", &dac->disc_LS}; + dinfo[14] = (info) {"shaper_test", &dac->shaper_test}; + dinfo[15] = (info) {"dac_disc_L", &dac->dac_disc_L}; + dinfo[16] = (info) {"dac_test", &dac->dac_test}; + dinfo[17] = (info) {"dac_disc_H", &dac->dac_disc_H}; + dinfo[18] = (info) {"delay", &dac->delay}; + dinfo[19] = (info) {"TP_buff_in", &dac->TP_buff_in}; + dinfo[20] = (info) {"TP_buff_out", &dac->TP_buff_out}; + dinfo[21] = (info) {"RPZ", &dac->RPZ}; + dinfo[22] = (info) {"GND", &dac->GND}; + dinfo[23] = (info) {"TP_ref", &dac->TP_ref}; + dinfo[24] = (info) {"FBK", &dac->FBK}; + dinfo[25] = (info) {"Cas", &dac->Cas}; + dinfo[26] = (info) {"TP_ref_A", &dac->TP_ref_A}; + dinfo[27] = (info) {"TP_ref_B", &dac->TP_ref_B}; + + *out_count = NUM_FIELDS; + return dinfo; +} diff --git a/src/mib_props_supp.c b/src/mib_props_supp.c deleted file mode 100644 index 3eb178a..0000000 --- a/src/mib_props_supp.c +++ /dev/null @@ -1,98 +0,0 @@ -#include "mib_props_supp.h" -#include "mib_header_DAC.h" -#include "mib_header_MQ1.h" -#include "mib_macros.h" -#include "mib_utils.h" -#include "mq1_quad.h" -#include "mq1_single.h" -#include "read_mq1_headers.h" -#include -#include - -/* Mainly this is just for easy access to mq1_fields and dac - */ - -info *mq1_fields_iter(MQ1_fields *fields_struct, size_t *out_count) -{ - if (!fields_struct || !out_count) - return NULL; - - const size_t NUM_FIELDS = 19; - - info *fields = malloc(NUM_FIELDS * sizeof(info)); - if (!fields) - return NULL; - - size_t i = 0; - - fields[i++] = (info) {"max_length", &fields_struct->max_length}; - fields[i++] = (info) {"sequence_number", fields_struct->sequence_number}; - fields[i++] = (info) {"header_bytes", fields_struct->header_bytes}; - fields[i++] = (info) {"num_chips", fields_struct->num_chips}; - fields[i++] = (info) {"det_x", fields_struct->det_x}; - fields[i++] = (info) {"det_y", fields_struct->det_y}; - fields[i++] = (info) {"pixel_depth", fields_struct->pixel_depth}; - fields[i++] = (info) {"sensor_layout", fields_struct->sensor_layout}; - fields[i++] = (info) {"chip_select", fields_struct->chip_select}; - fields[i++] = (info) {"timestamp", fields_struct->timestamp}; - fields[i++] = (info) {"exposure_time_s", fields_struct->exposure_time_s}; - fields[i++] = (info) {"counter", fields_struct->counter}; - fields[i++] = (info) {"colour_mode", fields_struct->colour_mode}; - fields[i++] = (info) {"gain_mode", fields_struct->gain_mode}; - fields[i++] = (info) {"threshold", fields_struct->threshold}; - fields[i++] = - (info) {"header_extension_id", fields_struct->header_extension_id}; - fields[i++] = - (info) {"extended_timestamp", fields_struct->extended_timestamp}; - fields[i++] = (info) {"exposure_time_ns", fields_struct->exposure_time_ns}; - fields[i++] = (info) {"bit_depth", fields_struct->bit_depth}; - - *out_count = NUM_FIELDS; - return fields; -} - -info *dac_iter(dac_rx *dac, size_t *out_count) -{ - if (!dac || !out_count) - return NULL; - - const size_t NUM_FIELDS = 28; - - info *dinfo = malloc(NUM_FIELDS * sizeof(info)); - if (!dinfo) - return NULL; - - size_t i = 0; - - dinfo[i++] = (info) {"dac_format", &dac->dac_format}; - dinfo[i++] = (info) {"threshold0", &dac->threshold0}; - dinfo[i++] = (info) {"threshold1", &dac->threshold1}; - dinfo[i++] = (info) {"threshold2", &dac->threshold2}; - dinfo[i++] = (info) {"threshold3", &dac->threshold3}; - dinfo[i++] = (info) {"threshold4", &dac->threshold4}; - dinfo[i++] = (info) {"threshold5", &dac->threshold5}; - dinfo[i++] = (info) {"threshold6", &dac->threshold6}; - dinfo[i++] = (info) {"threshold7", &dac->threshold7}; - dinfo[i++] = (info) {"preamp", &dac->preamp}; - dinfo[i++] = (info) {"ikrum", &dac->ikrum}; - dinfo[i++] = (info) {"shaper", &dac->shaper}; - dinfo[i++] = (info) {"disc", &dac->disc}; - dinfo[i++] = (info) {"disc_LS", &dac->disc_LS}; - dinfo[i++] = (info) {"shaper_test", &dac->shaper_test}; - dinfo[i++] = (info) {"dac_disc_L", &dac->dac_disc_L}; - dinfo[i++] = (info) {"dac_test", &dac->dac_test}; - dinfo[i++] = (info) {"dac_disc_H", &dac->dac_disc_H}; - dinfo[i++] = (info) {"delay", &dac->delay}; - dinfo[i++] = (info) {"TP_buff_in", &dac->TP_buff_in}; - dinfo[i++] = (info) {"TP_buff_out", &dac->TP_buff_out}; - dinfo[i++] = (info) {"RPZ", &dac->RPZ}; - dinfo[i++] = (info) {"GND", &dac->GND}; - dinfo[i++] = (info) {"TP_ref", &dac->TP_ref}; - dinfo[i++] = (info) {"FBK", &dac->FBK}; - dinfo[i++] = (info) {"Cas", &dac->Cas}; - dinfo[i++] = (info) {"TP_ref_A", &dac->TP_ref_A}; - dinfo[i++] = (info) {"TP_ref_B", &dac->TP_ref_B}; - - *out_count = NUM_FIELDS; - return dinfo; -} diff --git a/src/mq1_single.c b/src/mq1_single.c deleted file mode 100644 index 3bfb80f..0000000 --- a/src/mq1_single.c +++ /dev/null @@ -1,120 +0,0 @@ -#include "mq1_single.h" -#include "mib_header_MQ1.h" -#include "mib_macros.h" -#include "mib_utils.h" -#include -#include -#include - -/* this assumes the provided header is valid - * the header struct will be overwritten - */ -void parse_mq1_single(const char *header, mq1s *mq1_single) -{ - - int n = sscanf( - header, - "%[^,],%u,%u,%u,%u,%u,%[^,],%[^,],%[^,],%[^,]," - "%lf,%u,%u,%u,%f,%f,%f,%f,%f,%f,%f,%f," - "%[^,],%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%" - "u,%u,%u,%u,%u," - "%[^,],%[^,],%uns,%u", - mq1_single->header_id, &mq1_single->sequence_number, - &mq1_single->header_bytes, &mq1_single->num_chips, &mq1_single->det_x, - &mq1_single->det_y, mq1_single->pixel_depth, mq1_single->sensor_layout, - mq1_single->chip_select, mq1_single->timestamp, - &mq1_single->exposure_time_s, &mq1_single->counter, - &mq1_single->colour_mode, &mq1_single->gain_mode, &mq1_single->threshold[0], - &mq1_single->threshold[1], &mq1_single->threshold[2], - &mq1_single->threshold[3], &mq1_single->threshold[4], - &mq1_single->threshold[5], &mq1_single->threshold[6], - &mq1_single->threshold[7], mq1_single->dac0.dac_format, - &mq1_single->dac0.threshold0, &mq1_single->dac0.threshold1, - &mq1_single->dac0.threshold2, &mq1_single->dac0.threshold3, - &mq1_single->dac0.threshold4, &mq1_single->dac0.threshold5, - &mq1_single->dac0.threshold6, &mq1_single->dac0.threshold7, - &mq1_single->dac0.preamp, &mq1_single->dac0.ikrum, &mq1_single->dac0.shaper, - &mq1_single->dac0.disc, &mq1_single->dac0.disc_LS, - &mq1_single->dac0.shaper_test, &mq1_single->dac0.dac_disc_L, - &mq1_single->dac0.dac_test, &mq1_single->dac0.dac_disc_H, - &mq1_single->dac0.delay, &mq1_single->dac0.TP_buff_in, - &mq1_single->dac0.TP_buff_out, &mq1_single->dac0.RPZ, &mq1_single->dac0.GND, - &mq1_single->dac0.TP_ref, &mq1_single->dac0.FBK, &mq1_single->dac0.Cas, - &mq1_single->dac0.TP_ref_A, &mq1_single->dac0.TP_ref_B, - mq1_single->header_extension_id, mq1_single->extended_timestamp, - &mq1_single->exposure_time_ns, &mq1_single->bit_depth); - - if (n == EOF) { - const char *current_file = only_file_name(__FILE__); - fprintf(stderr, "%s:%d: error: the header appears to be empty\n", - current_file, __LINE__); - exit(1); - } else if (n != MQ1_SINGLE_HEADER_NUM_FIELDS) { - const char *current_file = only_file_name(__FILE__); - fprintf(stderr, "%s:%d: error: failed to match the MQ1 Quad header\n", - current_file, __LINE__); - exit(1); - } -} - -void print_single_mib_header(mq1s header) -{ - /* Assume the MQ1 Single header (mq1s) has been initialised, - * otherwise you should treat the printed values as garbages. - */ - printf("header id: %3s\n", header.header_id); - printf("sequence number: %u\n", header.sequence_number); - printf("header bytes: %u\n", header.header_bytes); - printf("number of chip(s): %u\n", header.num_chips); - printf("detector size in x: %u\n", header.det_x); - printf("detector size in y: %u\n", header.det_y); - printf("pixel data type: %3s\n", header.pixel_depth); - printf("sensor layout: %6s\n", header.sensor_layout); - printf("chip selected: %2s\n", header.chip_select); - printf("time stamp: %26s\n", header.timestamp); - printf("exposure time (s): %lf\n", header.exposure_time_s); - printf("counter: %u\n", header.counter); - printf("colour mode: %u\n", header.colour_mode); - printf("gain mode: %u\n", header.gain_mode); - printf("threshold 0: %f keV\n", header.threshold[0]); - printf("threshold 1: %f keV\n", header.threshold[1]); - printf("threshold 2: %f keV\n", header.threshold[2]); - printf("threshold 3: %f keV\n", header.threshold[3]); - printf("threshold 4: %f keV\n", header.threshold[4]); - printf("threshold 5: %f keV\n", header.threshold[5]); - printf("threshold 6: %f keV\n", header.threshold[6]); - printf("threshold 7: %f keV\n", header.threshold[7]); - puts("DAC 0:"); - printf("\t DAC format: %3s\n", header.dac0.dac_format); - printf("\t threshold0: %u\n", header.dac0.threshold0); - printf("\t threshold1: %u\n", header.dac0.threshold1); - printf("\t threshold2: %u\n", header.dac0.threshold2); - printf("\t threshold3: %u\n", header.dac0.threshold3); - printf("\t threshold4: %u\n", header.dac0.threshold4); - printf("\t threshold5: %u\n", header.dac0.threshold5); - printf("\t threshold6: %u\n", header.dac0.threshold6); - printf("\t threshold7: %u\n", header.dac0.threshold7); - printf("\t preamp: %u\n", header.dac0.preamp); - printf("\t ikrum: %u\n", header.dac0.ikrum); - printf("\t shaper: %u\n", header.dac0.shaper); - printf("\t disc: %u\n", header.dac0.disc); - printf("\t disc_LS: %u\n", header.dac0.disc_LS); - printf("\t shaper_test: %u\n", header.dac0.shaper_test); - printf("\t dac_disc_L: %u\n", header.dac0.dac_disc_L); - printf("\t dac_test: %u\n", header.dac0.dac_test); - printf("\t dac_disc_H: %u\n", header.dac0.dac_disc_H); - printf("\t delay: %u\n", header.dac0.delay); - printf("\t TP_buff_in: %u\n", header.dac0.TP_buff_in); - printf("\t TP_buff_out: %u\n", header.dac0.TP_buff_out); - printf("\t RPZ: %u\n", header.dac0.RPZ); - printf("\t GND: %u\n", header.dac0.GND); - printf("\t TP_ref: %u\n", header.dac0.TP_ref); - printf("\t FBK: %u\n", header.dac0.FBK); - printf("\t Cas: %u\n", header.dac0.Cas); - printf("\t TP_ref_A: %u\n", header.dac0.TP_ref_A); - printf("\t TP_ref_B: %u\n", header.dac0.TP_ref_B); - printf("header extension id: %4s\n", header.header_extension_id); - printf("extended time stamp: %28s\n", header.extended_timestamp); - printf("exposure time (ns): %u\n", header.exposure_time_ns); - printf("pixel bit depth: %u\n", header.bit_depth); -} diff --git a/src/mq1_quad.c b/src/parser.c similarity index 69% rename from src/mq1_quad.c rename to src/parser.c index 690f5fd..6315a11 100644 --- a/src/mq1_quad.c +++ b/src/parser.c @@ -1,11 +1,126 @@ -#include "mq1_quad.h" -#include "mib_header_MQ1.h" +#include "parser.h" +#include "io_header.h" +#include "mib_header.h" #include "mib_macros.h" -#include "mib_utils.h" +#include "utils.h" + #include #include #include +/* this assumes the provided header is valid + * the header struct will be overwritten + */ +void parse_mq1_single(const char *header, mq1s *mq1_single) +{ + + int n = sscanf( + header, + "%[^,],%u,%u,%u,%u,%u,%[^,],%[^,],%[^,],%[^,]," + "%lf,%u,%u,%u,%f,%f,%f,%f,%f,%f,%f,%f," + "%[^,],%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%" + "u,%u,%u,%u,%u," + "%[^,],%[^,],%uns,%u", + mq1_single->header_id, &mq1_single->sequence_number, + &mq1_single->header_bytes, &mq1_single->num_chips, &mq1_single->det_x, + &mq1_single->det_y, mq1_single->pixel_depth, mq1_single->sensor_layout, + mq1_single->chip_select, mq1_single->timestamp, + &mq1_single->exposure_time_s, &mq1_single->counter, + &mq1_single->colour_mode, &mq1_single->gain_mode, &mq1_single->threshold[0], + &mq1_single->threshold[1], &mq1_single->threshold[2], + &mq1_single->threshold[3], &mq1_single->threshold[4], + &mq1_single->threshold[5], &mq1_single->threshold[6], + &mq1_single->threshold[7], mq1_single->dac0.dac_format, + &mq1_single->dac0.threshold0, &mq1_single->dac0.threshold1, + &mq1_single->dac0.threshold2, &mq1_single->dac0.threshold3, + &mq1_single->dac0.threshold4, &mq1_single->dac0.threshold5, + &mq1_single->dac0.threshold6, &mq1_single->dac0.threshold7, + &mq1_single->dac0.preamp, &mq1_single->dac0.ikrum, &mq1_single->dac0.shaper, + &mq1_single->dac0.disc, &mq1_single->dac0.disc_LS, + &mq1_single->dac0.shaper_test, &mq1_single->dac0.dac_disc_L, + &mq1_single->dac0.dac_test, &mq1_single->dac0.dac_disc_H, + &mq1_single->dac0.delay, &mq1_single->dac0.TP_buff_in, + &mq1_single->dac0.TP_buff_out, &mq1_single->dac0.RPZ, &mq1_single->dac0.GND, + &mq1_single->dac0.TP_ref, &mq1_single->dac0.FBK, &mq1_single->dac0.Cas, + &mq1_single->dac0.TP_ref_A, &mq1_single->dac0.TP_ref_B, + mq1_single->header_extension_id, mq1_single->extended_timestamp, + &mq1_single->exposure_time_ns, &mq1_single->bit_depth); + + if (n == EOF) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: the header appears to be empty\n", + current_file, __LINE__); + exit(1); + } else if (n != MQ1_SINGLE_HEADER_NUM_FIELDS) { + const char *current_file = only_file_name(__FILE__); + fprintf(stderr, "%s:%d: error: failed to match the MQ1 Quad header\n", + current_file, __LINE__); + exit(1); + } +} + +void print_single_mib_header(mq1s header) +{ + /* Assume the MQ1 Single header (mq1s) has been initialised, + * otherwise you should treat the printed values as garbages. + */ + printf("header id: %3s\n", header.header_id); + printf("sequence number: %u\n", header.sequence_number); + printf("header bytes: %u\n", header.header_bytes); + printf("number of chip(s): %u\n", header.num_chips); + printf("detector size in x: %u\n", header.det_x); + printf("detector size in y: %u\n", header.det_y); + printf("pixel data type: %3s\n", header.pixel_depth); + printf("sensor layout: %6s\n", header.sensor_layout); + printf("chip selected: %2s\n", header.chip_select); + printf("time stamp: %26s\n", header.timestamp); + printf("exposure time (s): %lf\n", header.exposure_time_s); + printf("counter: %u\n", header.counter); + printf("colour mode: %u\n", header.colour_mode); + printf("gain mode: %u\n", header.gain_mode); + printf("threshold 0: %f keV\n", header.threshold[0]); + printf("threshold 1: %f keV\n", header.threshold[1]); + printf("threshold 2: %f keV\n", header.threshold[2]); + printf("threshold 3: %f keV\n", header.threshold[3]); + printf("threshold 4: %f keV\n", header.threshold[4]); + printf("threshold 5: %f keV\n", header.threshold[5]); + printf("threshold 6: %f keV\n", header.threshold[6]); + printf("threshold 7: %f keV\n", header.threshold[7]); + puts("DAC 0:"); + printf("\t DAC format: %3s\n", header.dac0.dac_format); + printf("\t threshold0: %u\n", header.dac0.threshold0); + printf("\t threshold1: %u\n", header.dac0.threshold1); + printf("\t threshold2: %u\n", header.dac0.threshold2); + printf("\t threshold3: %u\n", header.dac0.threshold3); + printf("\t threshold4: %u\n", header.dac0.threshold4); + printf("\t threshold5: %u\n", header.dac0.threshold5); + printf("\t threshold6: %u\n", header.dac0.threshold6); + printf("\t threshold7: %u\n", header.dac0.threshold7); + printf("\t preamp: %u\n", header.dac0.preamp); + printf("\t ikrum: %u\n", header.dac0.ikrum); + printf("\t shaper: %u\n", header.dac0.shaper); + printf("\t disc: %u\n", header.dac0.disc); + printf("\t disc_LS: %u\n", header.dac0.disc_LS); + printf("\t shaper_test: %u\n", header.dac0.shaper_test); + printf("\t dac_disc_L: %u\n", header.dac0.dac_disc_L); + printf("\t dac_test: %u\n", header.dac0.dac_test); + printf("\t dac_disc_H: %u\n", header.dac0.dac_disc_H); + printf("\t delay: %u\n", header.dac0.delay); + printf("\t TP_buff_in: %u\n", header.dac0.TP_buff_in); + printf("\t TP_buff_out: %u\n", header.dac0.TP_buff_out); + printf("\t RPZ: %u\n", header.dac0.RPZ); + printf("\t GND: %u\n", header.dac0.GND); + printf("\t TP_ref: %u\n", header.dac0.TP_ref); + printf("\t FBK: %u\n", header.dac0.FBK); + printf("\t Cas: %u\n", header.dac0.Cas); + printf("\t TP_ref_A: %u\n", header.dac0.TP_ref_A); + printf("\t TP_ref_B: %u\n", header.dac0.TP_ref_B); + printf("header extension id: %4s\n", header.header_extension_id); + printf("extended time stamp: %28s\n", header.extended_timestamp); + printf("exposure time (ns): %u\n", header.exposure_time_ns); + printf("pixel bit depth: %u\n", header.bit_depth); +} + /* this assumes the provided header is valid * the header struct will be overwritten */ diff --git a/src/mib_utils.c b/src/utils.c similarity index 99% rename from src/mib_utils.c rename to src/utils.c index 5e808a2..4f8dc02 100644 --- a/src/mib_utils.c +++ b/src/utils.c @@ -1,4 +1,4 @@ -#include "mib_utils.h" +#include "utils.h" #include #include From f0e58ec3793f6d6f8f80956660a7be9928deeeab Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 9 Apr 2025 16:40:09 +0100 Subject: [PATCH 015/251] Add free mq1_header part in framebuffer.c --- src/framebuffer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/framebuffer.c b/src/framebuffer.c index 96bd541..8f8819a 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -20,6 +20,11 @@ void free_frame(framebuffer *fb) free(fb->dac2); if (fb->dac3) free(fb->dac3); + if (fb->mq1_header) { + deallocate_MQ1_fields(fb->mq1_header); + free(fb->mq1_header); + fb->mq1_header = NULL; + } fb->rows = NULL; fb->data = NULL; fb->dac0 = NULL; From 566ebd4cbb8c80ec788a4ca3ad02c0432d750837 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 10 Apr 2025 10:13:38 +0100 Subject: [PATCH 016/251] Change name of marcos.h, remove some excessive header --- include/framebuffer.h | 9 --------- include/io_header.h | 5 ++--- include/{mib_macros.h => macros.h} | 0 include/mib_header.h | 2 +- include/parser.h | 2 +- src/framebuffer.c | 6 +++++- src/io_header.c | 6 ++---- src/parser.c | 2 +- 8 files changed, 12 insertions(+), 20 deletions(-) rename include/{mib_macros.h => macros.h} (100%) diff --git a/include/framebuffer.h b/include/framebuffer.h index 7c78909..61536e5 100644 --- a/include/framebuffer.h +++ b/include/framebuffer.h @@ -2,15 +2,6 @@ #ifndef FRAMEBUFFER_H #define FRAMEBUFFER_H -#include "mib_header_DAC.h" -#include "mib_header_MQ1.h" -#include "mib_macros.h" -#include "mib_utils.h" -#include "mq1_quad.h" -#include "mq1_single.h" -#include "read_mq1_headers.h" -#include - typedef struct { MQ1_fields *mq1_header; dac_rx *dac0; diff --git a/include/io_header.h b/include/io_header.h index ee981d4..99607e9 100644 --- a/include/io_header.h +++ b/include/io_header.h @@ -1,7 +1,6 @@ // clang-format Language: C -#include "mib_header_DAC.h" -#include "mib_header_MQ1.h" -#include "read_mq1_headers.h" +#include "mib_header.h" + #include #include #include diff --git a/include/mib_macros.h b/include/macros.h similarity index 100% rename from include/mib_macros.h rename to include/macros.h diff --git a/include/mib_header.h b/include/mib_header.h index 928598e..55f1870 100644 --- a/include/mib_header.h +++ b/include/mib_header.h @@ -1,5 +1,5 @@ // clang-format Language: C -#include "mib_macros.h" +#include "macros.h" #ifndef MIB_HEADER_DAC_RX_H #define MIB_HEADER_DAC_RX_H diff --git a/include/parser.h b/include/parser.h index aa2a5a7..cfe16e2 100644 --- a/include/parser.h +++ b/include/parser.h @@ -1,5 +1,5 @@ // clang-format Language: C -#include "mib_header_MQ1.h" +#include "mib_header.h" #ifndef PARSE_MQ1_SINGLE_H #define PARSE_MQ1_SINGLE_H diff --git a/src/framebuffer.c b/src/framebuffer.c index 8f8819a..00560eb 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -1,5 +1,5 @@ #include "framebuffer.h" -#include "mib_macros.h" +#include "macros.h" #include "utils.h" #include #include @@ -8,6 +8,10 @@ void free_frame(framebuffer *fb) { + if (fb == NULL) { + fprintf(stderr, "NULL framebuffer\n"); + return; + } if (fb->rows) free(fb->rows); if (fb->data) diff --git a/src/io_header.c b/src/io_header.c index 4ad7b3b..21a536b 100644 --- a/src/io_header.c +++ b/src/io_header.c @@ -1,8 +1,7 @@ #include "io_header.h" +#include "macros.h" #include "mib_header.h" -#include "mib_macros.h" #include "parser.h" -#include "read_mq1_headers.h" #include "utils.h" #include #include @@ -436,7 +435,7 @@ info *mq1_fields_info(MQ1_fields *fields_struct, size_t num_count) info *dac_info(dac_rx *dac, size_t num_count) { - if (!dac || !out_count) + if (!dac || !num_count) return NULL; if (num_count != 28) { @@ -477,6 +476,5 @@ info *dac_info(dac_rx *dac, size_t num_count) dinfo[26] = (info) {"TP_ref_A", &dac->TP_ref_A}; dinfo[27] = (info) {"TP_ref_B", &dac->TP_ref_B}; - *out_count = NUM_FIELDS; return dinfo; } diff --git a/src/parser.c b/src/parser.c index 6315a11..acaabed 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,7 +1,7 @@ #include "parser.h" #include "io_header.h" +#include "macros.h" #include "mib_header.h" -#include "mib_macros.h" #include "utils.h" #include From 1525110a0ae37c1fa9eea553978d4722e0f5e4fd Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 10 Apr 2025 10:32:29 +0100 Subject: [PATCH 017/251] Re-factored header guards --- include/framebuffer.h | 3 +++ include/io_header.h | 31 ++----------------------------- include/mib_header.h | 13 ++----------- include/parser.h | 13 ++----------- include/utils.h | 11 +++-------- 5 files changed, 12 insertions(+), 59 deletions(-) diff --git a/include/framebuffer.h b/include/framebuffer.h index 61536e5..e2a4c8a 100644 --- a/include/framebuffer.h +++ b/include/framebuffer.h @@ -1,4 +1,7 @@ // clang-format Language: C +#include "io_header.h" +#include "mib_header.h" + #ifndef FRAMEBUFFER_H #define FRAMEBUFFER_H diff --git a/include/io_header.h b/include/io_header.h index 99607e9..6baf33d 100644 --- a/include/io_header.h +++ b/include/io_header.h @@ -5,8 +5,8 @@ #include #include -#ifndef MQ1_FIELDS_H -#define MQ1_FIELDS_H +#ifndef IO_HEADER_H +#define IO_HEADER_H typedef struct { unsigned int max_length; @@ -30,56 +30,29 @@ typedef struct { unsigned int *bit_depth; } MQ1_fields; -#endif - -#ifndef ALLOCATE_MQ1_FIELDS_H -#define ALLOCATE_MQ1_FIELDS_H - MQ1_fields allocate_MQ1_fields(unsigned int nheaders); -#endif - -#ifndef DEALLOCATE_MQ1_FIELDS_H -#define DEALLOCATE_MQ1_FIELDS_H - void deallocate_MQ1_fields(MQ1_fields mq1_fields); -#endif - -#ifndef MQ1_SINGLE_FROM_FILE_H -#define MQ1_SINGLE_FROM_FILE_H unsigned int mq1_single_from_file(FILE *mib_ptr, unsigned int nheaders, unsigned int detector_frame_bytes, mq1s *mq1s_h, MQ1_fields *mq1_fields); -#endif -#ifndef MQ1_QUAD_FROM_FILE_H -#define MQ1_QUAD_FROM_FILE_H unsigned int mq1_quad_from_file(FILE *mib_ptr, unsigned int nheaders, unsigned int detector_frame_bytes, mq1q *mq1q_h, MQ1_fields *mq1_fields); -#endif -#ifndef FILL_MQ1_SINGLE_FIELDS_H -#define FILL_MQ1_SINGLE_FIELDS_H void fill_MQ1_single_fields(MQ1_fields *mq1_field, unsigned int index, mq1s mq1_h); -#endif -#ifndef FILL_MQ1_QUAD_FIELDS_H -#define FILL_MQ1_QUAD_FIELDS_H void fill_MQ1_quad_fields(MQ1_fields *mq1_field, unsigned int index, mq1q mq1_h); -#endif - -#ifndef MQ1_FIELD_ITER_H -#define MQ1_FIELD_ITER_H typedef struct { const char *name; diff --git a/include/mib_header.h b/include/mib_header.h index 55f1870..f458347 100644 --- a/include/mib_header.h +++ b/include/mib_header.h @@ -1,7 +1,7 @@ // clang-format Language: C #include "macros.h" -#ifndef MIB_HEADER_DAC_RX_H -#define MIB_HEADER_DAC_RX_H +#ifndef MIB_HEADER_H +#define MIB_HEADER_H typedef struct { char dac_format[4]; @@ -34,7 +34,6 @@ typedef struct { unsigned int TP_ref_B; } dac_rx; -#endif /* field 1: header ID (MQ1) field 2: sequence number of a frame @@ -64,9 +63,6 @@ field 54 / 138 : the pixel data bit depth The remainings are null bytes for padding. */ -#ifndef MIB_HEADER_MQ1_SINGLE_H -#define MIB_HEADER_MQ1_SINGLE_H - typedef struct { char header_id[MQ1_CHAR_LEN_HEADER_ID]; unsigned int sequence_number; @@ -90,11 +86,6 @@ typedef struct { unsigned int bit_depth; } mq1s; -#endif - -#ifndef MIB_HEADER_MQ1_QUAD_H -#define MIB_HEADER_MQ1_QUAD_H - typedef struct { char header_id[MQ1_CHAR_LEN_HEADER_ID]; unsigned int sequence_number; diff --git a/include/parser.h b/include/parser.h index cfe16e2..8b59df2 100644 --- a/include/parser.h +++ b/include/parser.h @@ -1,22 +1,13 @@ // clang-format Language: C #include "mib_header.h" -#ifndef PARSE_MQ1_SINGLE_H -#define PARSE_MQ1_SINGLE_H +#ifndef PARSER_H +#define PARSER_H void parse_mq1_single(const char *header, mq1s *mq1_single); -#endif -#ifndef PRINT_SINGLE_MIB_HEADER_H -#define PRINT_SINGLE_MIB_HEADER_H void print_single_mib_header(mq1s header); -#endif -#ifndef PARSE_MQ1_QUAD_H -#define PARSE_MQ1_QUAD_H void parse_mq1_quad(const char *header, mq1q *mq1_quad); -#endif -#ifndef PRINT_QUAD_MIB_HEADER_H -#define PRINT_QUAD_MIB_HEADER_H void print_quad_mib_header(mq1q header); #endif diff --git a/include/utils.h b/include/utils.h index eb68b37..7105499 100644 --- a/include/utils.h +++ b/include/utils.h @@ -1,18 +1,13 @@ // clang-format Language: C #include -#ifndef ONLY_FILE_NAME_H -#define ONLY_FILE_NAME_H +#ifndef UTILS_H +#define UTILS_H + const char *only_file_name(const char *absolute_file_path); -#endif /*ONLY_FILE_NAME_H*/ -#ifndef NUM_OF_HEADERS_H -#define NUM_OF_HEADERS_H unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride); -#endif -#ifndef HEADER_META_FROM_FIRST_H -#define HEADER_META_FROM_FIRST_H void header_meta_from_first(FILE *mib_ptr, char *header_id, unsigned int *header_bytes, From aa0d9bd7efabcd0a1abcd08b987e6e69de1d0a6b Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Fri, 11 Apr 2025 11:31:02 +0100 Subject: [PATCH 018/251] Added allocate_frame_header, allocate_frame_data. Changed free_frame to deallocate_frame. Added comments in framebuffer. Fixed some typo and leftover. --- include/framebuffer.h | 25 ++++++--- include/io_header.h | 4 +- include/macros.h | 8 +++ src/framebuffer.c | 114 +++++++++++++++++++++++++++++++++++++++++- src/io_header.c | 3 +- 5 files changed, 142 insertions(+), 12 deletions(-) diff --git a/include/framebuffer.h b/include/framebuffer.h index e2a4c8a..084fe24 100644 --- a/include/framebuffer.h +++ b/include/framebuffer.h @@ -6,15 +6,24 @@ #define FRAMEBUFFER_H typedef struct { - MQ1_fields *mq1_header; - dac_rx *dac0; - dac_rx *dac1; - dac_rx *dac2; - dac_rx *dac3; - void **rows; - void *data; + /* This struct is to hold the data inside a frame */ + MQ1_fields *mq1_header; // metadata for the frame + dac_rx *dac0; // dac0 for both single and quad headers + dac_rx *dac1; // dac1 for quad(if the header is single then this will be NULL + dac_rx *dac2; // dac2 for quad(same as dac1) + dac_rx *dac3; // dac3 for quad(same as dac1) + void **rows; // just a holder for easy access of actual data, i.e. can be used + // like fb->rows[i][j] + void *data; // row-major array for storing converted binary data in the frame } framebuffer; -void free_frame(framebuffer *fb); +// allocate memory for header in framebuffer +void allocate_frame_header(framebuffer *fb); + +// allocate memory for data in framebuffer +void allocate_frame_data(framebuffer *fb); + +// this is responsible for freeing the whole struct +void deallocate_frame(framebuffer *fb); #endif diff --git a/include/io_header.h b/include/io_header.h index 6baf33d..2befe34 100644 --- a/include/io_header.h +++ b/include/io_header.h @@ -59,7 +59,7 @@ typedef struct { void *data; } info; -info *mq1_fields_iter(MQ1_fields *fields, size_t *out_count); -info *dac_iter(dac_rx *dac, size_t *out_count); +info *mq1_fields_info(MQ1_fields *fields, size_t *out_count); +info *dac_info(dac_rx *dac, size_t *out_count); #endif diff --git a/include/macros.h b/include/macros.h index c12a846..4009151 100644 --- a/include/macros.h +++ b/include/macros.h @@ -46,3 +46,11 @@ #ifndef MQ1_CHAR_LEN_EXTENDED_TIMESTAMP #define MQ1_CHAR_LEN_EXTENDED_TIMESTAMP 31 #endif + +#ifndef MQ1_NUM_FIELDS +#define MQ1_NUM_FIELDS 19 +#endif + +#ifndef DAC_NUM_FIELDS +#define DAC_NUM_FIELDS 28 +#endif diff --git a/src/framebuffer.c b/src/framebuffer.c index 00560eb..b14707b 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -1,3 +1,15 @@ +/* These are the memory allocation functions of he struct framebuffer declared + * in framebuffer.h + * + * allocate_frame_header only allocates mq1_header and dacs in framebuffer + * allocate_frame_data only allocates rows and data in framebuffer + * + * Please check if both of them have been used before any usage on the struct + * + * Please also call deallocate_frame for freeing the memory. deallocate_frame + * frees both header and data + */ + #include "framebuffer.h" #include "macros.h" #include "utils.h" @@ -6,7 +18,107 @@ #include #include -void free_frame(framebuffer *fb) +void allocate_frame_header(framebuffer *fb) +{ + fb->mq1_header = malloc(sizeof(MQ1_fields)); + if (!mq1_header) { + fprintf(stderr, + "Error in malloc for mq1_header in allocate_frame_header\n"); + return; + } + fb->mq1_header = allocate_MQ1_fields(1); + fb->dac0 = (dac_rx *) malloc(sizeof(dac_rx)); + if (!fb->dac0) { + fprintf(stderr, "Error in malloc for dac0 in allocate_frame_header\n"); + return; + } + fb->mq1_header = allocate_MQ1_fields(1); + fb->dac1 = (dac_rx *) malloc(sizeof(dac_rx)); + if (!fb->dac1) { + fprintf(stderr, "Error in malloc for dac1 in allocate_frame_header\n"); + return; + } + fb->dac2 = (dac_rx *) malloc(sizeof(dac_rx)); + if (!fb->dac2) { + fprintf(stderr, "Error in malloc for dac2 in allocate_frame_header\n"); + return; + } + fb->dac3 = (dac_rx *) malloc(sizeof(dac_rx)); + if (!fb->dac3) { + fprintf(stderr, "Error in malloc for dac3 in allocate_frame_header\n"); + return; + } +} + +void allocate_frame_data(framebuffer *fb) +{ + int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + + (fb->mq1_header->pixel_depth[2] - '0'); + bufsize = bufsize / 8; + + int detx = (int) *(fb->mq1_header->det_x); + int dety = (int) *(fb->mq1_header->det_y); + + fb->rows = malloc(sizeof(void *) * dety); + if (!fb->rows) { + fprintf(stderr, "Error in malloc for fb->rows in allocate_frame_data\n"); + return; + } + fb->data = NULL; + switch (bufsize) { + case 1: { + fb->data = malloc(sizeof(uint8_t) * detx * dety); + if (!data) { + fprintf(stderr, "malloc failed for data in read_frame"); + return; + } + for (int i = 0; i < (int) dety; i++) { + fb->rows[i] = (uint8_t *) data + i * detx; + } + break; + } + case 2: { + fb->data = malloc(sizeof(uint16_t) * detx * dety); + if (!data) { + fprintf(stderr, "malloc failed for data in read_frame"); + return; + } + for (int i = 0; i < (int) dety; i++) { + fb->rows[i] = (uint16_t *) data + i * detx; + } + break; + } + case 4: { + fb->data = malloc(sizeof(uint32_t) * detx * dety); + if (!data) { + fprintf(stderr, "malloc failed for data in read_frame"); + return; + } + for (int i = 0; i < (int) dety; i++) { + fb->rows[i] = (uint32_t *) data + i * detx; + } + break; + } + case 8: { + fb->data = malloc(sizeof(uint64_t) * detx * dety); + if (!data) { + fprintf(stderr, "malloc failed for data in read_frame"); + return; + } + for (int i = 0; i < (int) dety; i++) { + fb->rows[i] = (uint64_t *) data + i * detx; + } + break; + } + default: + printf("Unsupported pixel depth, single bit will be implemented later\n"); + if (fb->data) + free(fb->data); + return; + } +} + +void deallocate_frame(framebuffer *fb) { if (fb == NULL) { fprintf(stderr, "NULL framebuffer\n"); diff --git a/src/io_header.c b/src/io_header.c index 21a536b..87cbdda 100644 --- a/src/io_header.c +++ b/src/io_header.c @@ -393,6 +393,7 @@ void fill_MQ1_quad_fields(MQ1_fields *mq1_field, unsigned int index, mq1q mq1_h) } /* Mainly this is just for easy access to mq1_fields and dac + * Please free the returning array after using it */ info *mq1_fields_info(MQ1_fields *fields_struct, size_t num_count) @@ -443,7 +444,7 @@ info *dac_info(dac_rx *dac, size_t num_count) return NULL; } - info *dinfo = malloc(NUM_FIELDS * sizeof(info)); + info *dinfo = malloc(num_count * sizeof(info)); if (!dinfo) return NULL; From ac32e27c19b1e89167eacde592ec9c7364fd7540 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Fri, 11 Apr 2025 11:34:17 +0100 Subject: [PATCH 019/251] Remove bin, modified config.mk --- config.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.mk b/config.mk index d2b5a00..89b0dee 100644 --- a/config.mk +++ b/config.mk @@ -1,7 +1,6 @@ # === Directories === SRCDIR := src OBJDIR := obj -BINDIR ?= bin INCDIR := include HDFDIR ?= $(HDF5_ROOT) @@ -34,4 +33,4 @@ SOURCES := $(wildcard $(SRCDIR)/*.c) OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SOURCES)) -TARGET := $(BINDIR)/mib2h5 +TARGET := mib2h5 From 6ae5a460d6f1560adab3855bb12d1dd363b319ef Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 17 Apr 2025 10:11:31 +0100 Subject: [PATCH 020/251] Fix typo in allocate_frame_data --- src/framebuffer.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index b14707b..85c3296 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -59,61 +59,67 @@ void allocate_frame_data(framebuffer *fb) int detx = (int) *(fb->mq1_header->det_x); int dety = (int) *(fb->mq1_header->det_y); - fb->rows = malloc(sizeof(void *) * dety); - if (!fb->rows) { + void **buffer = malloc(sizeof(void *) * dety); + if (!buffer) { fprintf(stderr, "Error in malloc for fb->rows in allocate_frame_data\n"); return; } - fb->data = NULL; + void *data - NULL; + fb->rows = buffer; switch (bufsize) { case 1: { - fb->data = malloc(sizeof(uint8_t) * detx * dety); + data = malloc(sizeof(uint8_t) * detx * dety); if (!data) { fprintf(stderr, "malloc failed for data in read_frame"); return; } + fb->data = data; for (int i = 0; i < (int) dety; i++) { - fb->rows[i] = (uint8_t *) data + i * detx; + buffer[i] = (uint8_t *) data + i * detx; } break; } case 2: { - fb->data = malloc(sizeof(uint16_t) * detx * dety); + data = malloc(sizeof(uint16_t) * detx * dety); if (!data) { fprintf(stderr, "malloc failed for data in read_frame"); return; } + fb->data = data; for (int i = 0; i < (int) dety; i++) { - fb->rows[i] = (uint16_t *) data + i * detx; + buffer[i] = (uint16_t *) data + i * detx; } break; } case 4: { - fb->data = malloc(sizeof(uint32_t) * detx * dety); + data = malloc(sizeof(uint32_t) * detx * dety); if (!data) { fprintf(stderr, "malloc failed for data in read_frame"); return; } + fb->data = data; for (int i = 0; i < (int) dety; i++) { - fb->rows[i] = (uint32_t *) data + i * detx; + buffer[i] = (uint32_t *) data + i * detx; } break; } case 8: { - fb->data = malloc(sizeof(uint64_t) * detx * dety); + data = malloc(sizeof(uint64_t) * detx * dety); if (!data) { fprintf(stderr, "malloc failed for data in read_frame"); return; } + fb->data = data for (int i = 0; i < (int) dety; i++) { - fb->rows[i] = (uint64_t *) data + i * detx; + buffer[i] = (uint64_t *) data + i * detx; } break; } default: printf("Unsupported pixel depth, single bit will be implemented later\n"); - if (fb->data) - free(fb->data); + if (data) + free(data); + free(buffer); return; } } From aa303efff4185c4a6074a46c1a2ea7d19190d70a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 17 Apr 2025 10:16:33 +0100 Subject: [PATCH 021/251] Add compress_frame --- src/framebuffer.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/framebuffer.c b/src/framebuffer.c index 85c3296..58018cc 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -8,6 +8,8 @@ * * Please also call deallocate_frame for freeing the memory. deallocate_frame * frees both header and data + * + * compress_frame is used for compressing the data */ #include "framebuffer.h" @@ -124,6 +126,65 @@ void allocate_frame_data(framebuffer *fb) } } +/* This is to compress the data inside framebuffer->data + * The function will return the size of the data after compression + * which is from blosc_compress_ctx + */ +int compress_frame(framebuffer fb*, + unsigned int compression_level, + unsigned int shuffle, + char *compressor, + size_t blocksize, + int numinternalthreads) +{ + int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + + (fb->mq1_header->pixel_depth[2] - '0'); + bufsize = bufsize / 8; + + int detx = (int) *(fb->mq1_header->det_x); + int dety = (int) *(fb->mq1_header->det_y); + + size_t nbytes = dety * detx * bufsize; + size_t destsize = nbytes + BLOSC_MAX_OVERHEAD; + void *dest = malloc(destsize); + if (!dest) { + fprintf(stderr, "Error in malloc for dest\n"); + return -1; + } + + int cbytes = blosc_compress_ctx(compression_level, shuffle, bufsize, nbytes, + fb->data, dest, destsize, compressor, + blocksize, numinternalthreads); + if (cbytes < 0) { + fprintf(stderr, "Error in blosc_compress\n"); + free(dest); + return -1; + } + if (cbytes == 0) { + fprintf(stderr, "Blosc returned 0 bytes (uncompressible?). Forcing " + "fallback to uncompressed write.\n"); + cbytes = nbytes; + return cbytes; + } + // for showing compression ratio in each frame, profiling purposes + // if (cbytes != 0) { + // printf("compression: %ld -> %d (%.1fx)\n", nbytes, cbytes, (1. * nbytes) / + // cbytes); + //} + + free(fb->data); + fb->data = malloc(destsize); + if (!fb->data) { + fprintf(stderr, "Error in malloc for fb->data\n"); + free(dest); + return -1; + } + + memcpy(fb->data, dest, cbytes); + free(dest); + return cbytes; +} + void deallocate_frame(framebuffer *fb) { if (fb == NULL) { From 58d346c9fa73a7f3cf48bf28024f5015aeb3cb02 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 17 Apr 2025 10:19:21 +0100 Subject: [PATCH 022/251] Fix typo in allocate_frame_header --- src/framebuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index 58018cc..ef791c5 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -23,7 +23,7 @@ void allocate_frame_header(framebuffer *fb) { fb->mq1_header = malloc(sizeof(MQ1_fields)); - if (!mq1_header) { + if (!fb->mq1_header) { fprintf(stderr, "Error in malloc for mq1_header in allocate_frame_header\n"); return; From 1952a7e1e76e2bab2b6d427337bdbf95b240056f Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 17 Apr 2025 11:36:56 +0100 Subject: [PATCH 023/251] Change MQ1_NUM_FIELDS to MQ1_FIELDS_NUM_FIELDS --- include/macros.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/macros.h b/include/macros.h index 4009151..0b79839 100644 --- a/include/macros.h +++ b/include/macros.h @@ -47,8 +47,8 @@ #define MQ1_CHAR_LEN_EXTENDED_TIMESTAMP 31 #endif -#ifndef MQ1_NUM_FIELDS -#define MQ1_NUM_FIELDS 19 +#ifndef MQ1_FIELDS_NUM_FIELDS +#define MQ1_FIELDS_NUM_FIELDS 19 #endif #ifndef DAC_NUM_FIELDS From ff2783e93bac834c98ce4da02d76d2578abf5e6f Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 17 Apr 2025 11:40:28 +0100 Subject: [PATCH 024/251] Change mq1_fields_info to use macros --- include/io_header.h | 2 +- src/io_header.c | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/include/io_header.h b/include/io_header.h index 2befe34..d43b684 100644 --- a/include/io_header.h +++ b/include/io_header.h @@ -59,7 +59,7 @@ typedef struct { void *data; } info; -info *mq1_fields_info(MQ1_fields *fields, size_t *out_count); +info *mq1_fields_info(MQ1_fields *fields); info *dac_info(dac_rx *dac, size_t *out_count); #endif diff --git a/src/io_header.c b/src/io_header.c index 87cbdda..27024ac 100644 --- a/src/io_header.c +++ b/src/io_header.c @@ -396,17 +396,12 @@ void fill_MQ1_quad_fields(MQ1_fields *mq1_field, unsigned int index, mq1q mq1_h) * Please free the returning array after using it */ -info *mq1_fields_info(MQ1_fields *fields_struct, size_t num_count) +info *mq1_fields_info(MQ1_fields *fields_struct) { - if (!fields_struct || !num_count) + if (!fields_struct) return NULL; - if (num_count != 19) { - fprintf(stderr, "Wrong number of fields in mq1_fields_info\n"); - return NULL; - } - - info *fields = malloc(num_count * sizeof(info)); + info *fields = malloc(MQ1_FIELDS_NUM_FIELDS * sizeof(info)); if (!fields) return NULL; From d22c3dbf591fd7a12932011f31a1592285018c99 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 17 Apr 2025 11:42:03 +0100 Subject: [PATCH 025/251] Change dac_info to use macros --- include/io_header.h | 2 +- src/io_header.c | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/include/io_header.h b/include/io_header.h index d43b684..da02e0f 100644 --- a/include/io_header.h +++ b/include/io_header.h @@ -60,6 +60,6 @@ typedef struct { } info; info *mq1_fields_info(MQ1_fields *fields); -info *dac_info(dac_rx *dac, size_t *out_count); +info *dac_info(dac_rx *dac); #endif diff --git a/src/io_header.c b/src/io_header.c index 27024ac..766f61d 100644 --- a/src/io_header.c +++ b/src/io_header.c @@ -429,17 +429,12 @@ info *mq1_fields_info(MQ1_fields *fields_struct) return fields; } -info *dac_info(dac_rx *dac, size_t num_count) +info *dac_info(dac_rx *dac) { - if (!dac || !num_count) + if (!dac) return NULL; - if (num_count != 28) { - fprintf(stderr, "Wrong number of fields in dac_info\n"); - return NULL; - } - - info *dinfo = malloc(num_count * sizeof(info)); + info *dinfo = malloc(DAC_NUM_FIELDS * sizeof(info)); if (!dinfo) return NULL; From 76ecde8008fbc65e0a85b4b3025a98b97be585a5 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 17 Apr 2025 11:45:18 +0100 Subject: [PATCH 026/251] Add compress_frame in framebuffer.h --- include/framebuffer.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/framebuffer.h b/include/framebuffer.h index 084fe24..efff8b5 100644 --- a/include/framebuffer.h +++ b/include/framebuffer.h @@ -23,6 +23,14 @@ void allocate_frame_header(framebuffer *fb); // allocate memory for data in framebuffer void allocate_frame_data(framebuffer *fb); +// compress data inside framebuffer +int compress_frame(framebuffer *fb, + unsigned int compression_level, + unsigned int shuffle, + char *compressor, + size_t blocksize, + int numinternalthreads); + // this is responsible for freeing the whole struct void deallocate_frame(framebuffer *fb); From c2b0e79fd9a46d72d91650d557d5aaffb18c4bb4 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 13:20:59 +0100 Subject: [PATCH 027/251] Move header files to src --- include/framebuffer.h | 37 -------------- include/io_header.h | 65 ------------------------ include/macros.h | 56 -------------------- include/mib_header.h | 115 ------------------------------------------ include/parser.h | 13 ----- include/utils.h | 18 ------- 6 files changed, 304 deletions(-) delete mode 100644 include/framebuffer.h delete mode 100644 include/io_header.h delete mode 100644 include/macros.h delete mode 100644 include/mib_header.h delete mode 100644 include/parser.h delete mode 100644 include/utils.h diff --git a/include/framebuffer.h b/include/framebuffer.h deleted file mode 100644 index efff8b5..0000000 --- a/include/framebuffer.h +++ /dev/null @@ -1,37 +0,0 @@ -// clang-format Language: C -#include "io_header.h" -#include "mib_header.h" - -#ifndef FRAMEBUFFER_H -#define FRAMEBUFFER_H - -typedef struct { - /* This struct is to hold the data inside a frame */ - MQ1_fields *mq1_header; // metadata for the frame - dac_rx *dac0; // dac0 for both single and quad headers - dac_rx *dac1; // dac1 for quad(if the header is single then this will be NULL - dac_rx *dac2; // dac2 for quad(same as dac1) - dac_rx *dac3; // dac3 for quad(same as dac1) - void **rows; // just a holder for easy access of actual data, i.e. can be used - // like fb->rows[i][j] - void *data; // row-major array for storing converted binary data in the frame -} framebuffer; - -// allocate memory for header in framebuffer -void allocate_frame_header(framebuffer *fb); - -// allocate memory for data in framebuffer -void allocate_frame_data(framebuffer *fb); - -// compress data inside framebuffer -int compress_frame(framebuffer *fb, - unsigned int compression_level, - unsigned int shuffle, - char *compressor, - size_t blocksize, - int numinternalthreads); - -// this is responsible for freeing the whole struct -void deallocate_frame(framebuffer *fb); - -#endif diff --git a/include/io_header.h b/include/io_header.h deleted file mode 100644 index da02e0f..0000000 --- a/include/io_header.h +++ /dev/null @@ -1,65 +0,0 @@ -// clang-format Language: C -#include "mib_header.h" - -#include -#include -#include - -#ifndef IO_HEADER_H -#define IO_HEADER_H - -typedef struct { - unsigned int max_length; - unsigned int *sequence_number; - unsigned int *header_bytes; - unsigned int *num_chips; - unsigned int *det_x; - unsigned int *det_y; - char *pixel_depth; - char *sensor_layout; - char *chip_select; - char *timestamp; - double *exposure_time_s; - unsigned int *counter; - unsigned int *colour_mode; - unsigned int *gain_mode; - float *threshold; - char *header_extension_id; - char *extended_timestamp; - unsigned int *exposure_time_ns; - unsigned int *bit_depth; -} MQ1_fields; - -MQ1_fields allocate_MQ1_fields(unsigned int nheaders); - -void deallocate_MQ1_fields(MQ1_fields mq1_fields); - -unsigned int mq1_single_from_file(FILE *mib_ptr, - unsigned int nheaders, - unsigned int detector_frame_bytes, - mq1s *mq1s_h, - MQ1_fields *mq1_fields); - -unsigned int mq1_quad_from_file(FILE *mib_ptr, - unsigned int nheaders, - unsigned int detector_frame_bytes, - mq1q *mq1q_h, - MQ1_fields *mq1_fields); - -void fill_MQ1_single_fields(MQ1_fields *mq1_field, - unsigned int index, - mq1s mq1_h); - -void fill_MQ1_quad_fields(MQ1_fields *mq1_field, - unsigned int index, - mq1q mq1_h); - -typedef struct { - const char *name; - void *data; -} info; - -info *mq1_fields_info(MQ1_fields *fields); -info *dac_info(dac_rx *dac); - -#endif diff --git a/include/macros.h b/include/macros.h deleted file mode 100644 index 0b79839..0000000 --- a/include/macros.h +++ /dev/null @@ -1,56 +0,0 @@ -// clang-format Language: C -#ifndef MQ1_SINGLE_HEADER_BYTES -#define MQ1_SINGLE_HEADER_BYTES 384 -#endif - -#ifndef MQ1_SINGLE_HEADER_NUM_FIELDS -#define MQ1_SINGLE_HEADER_NUM_FIELDS 54 -#endif - -#ifndef MQ1_QUAD_HEADER_BYTES -#define MQ1_QUAD_HEADER_BYTES 768 -#endif - -#ifndef MQ1_QUAD_HEADER_NUM_FIELDS -#define MQ1_QUAD_HEADER_NUM_FIELDS 138 -#endif - -#ifndef MQ1_CHAR_LEN_HEADER_ID -#define MQ1_CHAR_LEN_HEADER_ID 4 -#endif - -#ifndef MQ1_CHAR_LEN_PIXEL_DEPTH -#define MQ1_CHAR_LEN_PIXEL_DEPTH 4 -#endif - -#ifndef MQ1_CHAR_LEN_SENSOR_LAYOUT -#define MQ1_CHAR_LEN_SENSOR_LAYOUT 7 -#endif - -#ifndef MQ1_CHAR_LEN_CHIP_SELECT -#define MQ1_CHAR_LEN_CHIP_SELECT 3 -#endif - -#ifndef MQ1_CHAR_LEN_TIMESTAMP -#define MQ1_CHAR_LEN_TIMESTAMP 27 -#endif - -#ifndef MQ1_FLOAT_LEN_THRESHOLD -#define MQ1_FLOAT_LEN_THRESHOLD 8 -#endif - -#ifndef MQ1_CHAR_LEN_HEADER_EXTENSION_ID -#define MQ1_CHAR_LEN_HEADER_EXTENSION_ID 5 -#endif - -#ifndef MQ1_CHAR_LEN_EXTENDED_TIMESTAMP -#define MQ1_CHAR_LEN_EXTENDED_TIMESTAMP 31 -#endif - -#ifndef MQ1_FIELDS_NUM_FIELDS -#define MQ1_FIELDS_NUM_FIELDS 19 -#endif - -#ifndef DAC_NUM_FIELDS -#define DAC_NUM_FIELDS 28 -#endif diff --git a/include/mib_header.h b/include/mib_header.h deleted file mode 100644 index f458347..0000000 --- a/include/mib_header.h +++ /dev/null @@ -1,115 +0,0 @@ -// clang-format Language: C -#include "macros.h" -#ifndef MIB_HEADER_H -#define MIB_HEADER_H - -typedef struct { - char dac_format[4]; - unsigned int threshold0; - unsigned int threshold1; - unsigned int threshold2; - unsigned int threshold3; - unsigned int threshold4; - unsigned int threshold5; - unsigned int threshold6; - unsigned int threshold7; - unsigned int preamp; - unsigned int ikrum; - unsigned int shaper; - unsigned int disc; - unsigned int disc_LS; - unsigned int shaper_test; - unsigned int dac_disc_L; - unsigned int dac_test; - unsigned int dac_disc_H; - unsigned int delay; - unsigned int TP_buff_in; - unsigned int TP_buff_out; - unsigned int RPZ; - unsigned int GND; - unsigned int TP_ref; - unsigned int FBK; - unsigned int Cas; - unsigned int TP_ref_A; - unsigned int TP_ref_B; -} dac_rx; - -/* -field 1: header ID (MQ1) -field 2: sequence number of a frame -field 3: the number of bytes of the header -field 4: the number of chips -field 5: the number of columns of the detector (x) -field 6: the number of rows of the detector (y) -field 7: the pixel data type (U01, U08, U16, U32, U64) -field 8: sensor layout (2x2, Nx1, 2x2G, Nx1G, with leading spaces) -field 9: active chip(s) during the capture of the frame, U8 hexadecimal repr -field 10: timestamp -field 11: shutter opening time (seconds) -field 12: counter 0 or 1 -field 13: colour mode, 0=monochrome image, 1=colour image -field 14: gain modem 0 = SLGM, 1 = LGM, 2 = HGM, 3 = SHGM -field 15-22: threshold values (keV) - -DAC of each chips contains 28 entries. - -Header extension - Single / Quad -field 51 / 135 : MQ1A -field 52 / 136 : UTC timestamp (time in ns) -field 53 / 137 : shutter opening time (with suffix "ns") -field 54 / 138 : the pixel data bit depth - -The remainings are null bytes for padding. -*/ - -typedef struct { - char header_id[MQ1_CHAR_LEN_HEADER_ID]; - unsigned int sequence_number; - unsigned int header_bytes; - unsigned int num_chips; - unsigned int det_x; - unsigned int det_y; - char pixel_depth[MQ1_CHAR_LEN_PIXEL_DEPTH]; - char sensor_layout[MQ1_CHAR_LEN_SENSOR_LAYOUT]; - char chip_select[MQ1_CHAR_LEN_CHIP_SELECT]; - char timestamp[MQ1_CHAR_LEN_TIMESTAMP]; - double exposure_time_s; - unsigned int counter; - unsigned int colour_mode; - unsigned int gain_mode; - float threshold[MQ1_FLOAT_LEN_THRESHOLD]; - dac_rx dac0; - char header_extension_id[MQ1_CHAR_LEN_HEADER_EXTENSION_ID]; - char extended_timestamp[MQ1_CHAR_LEN_EXTENDED_TIMESTAMP]; - unsigned int exposure_time_ns; - unsigned int bit_depth; -} mq1s; - -typedef struct { - char header_id[MQ1_CHAR_LEN_HEADER_ID]; - unsigned int sequence_number; - unsigned int header_bytes; - unsigned int num_chips; - unsigned int det_x; - unsigned int det_y; - char pixel_depth[MQ1_CHAR_LEN_PIXEL_DEPTH]; - char sensor_layout[MQ1_CHAR_LEN_SENSOR_LAYOUT]; - char chip_select[MQ1_CHAR_LEN_CHIP_SELECT]; - char timestamp[MQ1_CHAR_LEN_TIMESTAMP]; - double exposure_time_s; - unsigned int counter; - unsigned int colour_mode; - unsigned int gain_mode; - float threshold[MQ1_FLOAT_LEN_THRESHOLD]; - dac_rx dac0; - dac_rx dac1; - dac_rx dac2; - dac_rx dac3; - char header_extension_id[MQ1_CHAR_LEN_HEADER_EXTENSION_ID]; - char extended_timestamp[MQ1_CHAR_LEN_EXTENDED_TIMESTAMP]; - unsigned int exposure_time_ns; - unsigned int bit_depth; -} mq1q; - -#endif diff --git a/include/parser.h b/include/parser.h deleted file mode 100644 index 8b59df2..0000000 --- a/include/parser.h +++ /dev/null @@ -1,13 +0,0 @@ -// clang-format Language: C -#include "mib_header.h" - -#ifndef PARSER_H -#define PARSER_H -void parse_mq1_single(const char *header, mq1s *mq1_single); - -void print_single_mib_header(mq1s header); - -void parse_mq1_quad(const char *header, mq1q *mq1_quad); - -void print_quad_mib_header(mq1q header); -#endif diff --git a/include/utils.h b/include/utils.h deleted file mode 100644 index 7105499..0000000 --- a/include/utils.h +++ /dev/null @@ -1,18 +0,0 @@ -// clang-format Language: C -#include - -#ifndef UTILS_H -#define UTILS_H - -const char *only_file_name(const char *absolute_file_path); - -unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride); - -void header_meta_from_first(FILE *mib_ptr, - char *header_id, - unsigned int *header_bytes, - unsigned int *num_chips, - unsigned int *det_x, - unsigned int *det_y, - char *pixel_depth); -#endif From 7e4744d5fd6ea40051e62827bee184cd2c21232b Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 13:26:01 +0100 Subject: [PATCH 028/251] Add header files into src --- src/framebuffer.h | 37 +++++++++++++++ src/io_header.h | 65 ++++++++++++++++++++++++++ src/macros.h | 56 ++++++++++++++++++++++ src/mib_header.h | 115 ++++++++++++++++++++++++++++++++++++++++++++++ src/parser.h | 13 ++++++ src/utils.h | 18 ++++++++ 6 files changed, 304 insertions(+) create mode 100644 src/framebuffer.h create mode 100644 src/io_header.h create mode 100644 src/macros.h create mode 100644 src/mib_header.h create mode 100644 src/parser.h create mode 100644 src/utils.h diff --git a/src/framebuffer.h b/src/framebuffer.h new file mode 100644 index 0000000..efff8b5 --- /dev/null +++ b/src/framebuffer.h @@ -0,0 +1,37 @@ +// clang-format Language: C +#include "io_header.h" +#include "mib_header.h" + +#ifndef FRAMEBUFFER_H +#define FRAMEBUFFER_H + +typedef struct { + /* This struct is to hold the data inside a frame */ + MQ1_fields *mq1_header; // metadata for the frame + dac_rx *dac0; // dac0 for both single and quad headers + dac_rx *dac1; // dac1 for quad(if the header is single then this will be NULL + dac_rx *dac2; // dac2 for quad(same as dac1) + dac_rx *dac3; // dac3 for quad(same as dac1) + void **rows; // just a holder for easy access of actual data, i.e. can be used + // like fb->rows[i][j] + void *data; // row-major array for storing converted binary data in the frame +} framebuffer; + +// allocate memory for header in framebuffer +void allocate_frame_header(framebuffer *fb); + +// allocate memory for data in framebuffer +void allocate_frame_data(framebuffer *fb); + +// compress data inside framebuffer +int compress_frame(framebuffer *fb, + unsigned int compression_level, + unsigned int shuffle, + char *compressor, + size_t blocksize, + int numinternalthreads); + +// this is responsible for freeing the whole struct +void deallocate_frame(framebuffer *fb); + +#endif diff --git a/src/io_header.h b/src/io_header.h new file mode 100644 index 0000000..da02e0f --- /dev/null +++ b/src/io_header.h @@ -0,0 +1,65 @@ +// clang-format Language: C +#include "mib_header.h" + +#include +#include +#include + +#ifndef IO_HEADER_H +#define IO_HEADER_H + +typedef struct { + unsigned int max_length; + unsigned int *sequence_number; + unsigned int *header_bytes; + unsigned int *num_chips; + unsigned int *det_x; + unsigned int *det_y; + char *pixel_depth; + char *sensor_layout; + char *chip_select; + char *timestamp; + double *exposure_time_s; + unsigned int *counter; + unsigned int *colour_mode; + unsigned int *gain_mode; + float *threshold; + char *header_extension_id; + char *extended_timestamp; + unsigned int *exposure_time_ns; + unsigned int *bit_depth; +} MQ1_fields; + +MQ1_fields allocate_MQ1_fields(unsigned int nheaders); + +void deallocate_MQ1_fields(MQ1_fields mq1_fields); + +unsigned int mq1_single_from_file(FILE *mib_ptr, + unsigned int nheaders, + unsigned int detector_frame_bytes, + mq1s *mq1s_h, + MQ1_fields *mq1_fields); + +unsigned int mq1_quad_from_file(FILE *mib_ptr, + unsigned int nheaders, + unsigned int detector_frame_bytes, + mq1q *mq1q_h, + MQ1_fields *mq1_fields); + +void fill_MQ1_single_fields(MQ1_fields *mq1_field, + unsigned int index, + mq1s mq1_h); + +void fill_MQ1_quad_fields(MQ1_fields *mq1_field, + unsigned int index, + mq1q mq1_h); + +typedef struct { + const char *name; + void *data; +} info; + +info *mq1_fields_info(MQ1_fields *fields); +info *dac_info(dac_rx *dac); + +#endif diff --git a/src/macros.h b/src/macros.h new file mode 100644 index 0000000..0b79839 --- /dev/null +++ b/src/macros.h @@ -0,0 +1,56 @@ +// clang-format Language: C +#ifndef MQ1_SINGLE_HEADER_BYTES +#define MQ1_SINGLE_HEADER_BYTES 384 +#endif + +#ifndef MQ1_SINGLE_HEADER_NUM_FIELDS +#define MQ1_SINGLE_HEADER_NUM_FIELDS 54 +#endif + +#ifndef MQ1_QUAD_HEADER_BYTES +#define MQ1_QUAD_HEADER_BYTES 768 +#endif + +#ifndef MQ1_QUAD_HEADER_NUM_FIELDS +#define MQ1_QUAD_HEADER_NUM_FIELDS 138 +#endif + +#ifndef MQ1_CHAR_LEN_HEADER_ID +#define MQ1_CHAR_LEN_HEADER_ID 4 +#endif + +#ifndef MQ1_CHAR_LEN_PIXEL_DEPTH +#define MQ1_CHAR_LEN_PIXEL_DEPTH 4 +#endif + +#ifndef MQ1_CHAR_LEN_SENSOR_LAYOUT +#define MQ1_CHAR_LEN_SENSOR_LAYOUT 7 +#endif + +#ifndef MQ1_CHAR_LEN_CHIP_SELECT +#define MQ1_CHAR_LEN_CHIP_SELECT 3 +#endif + +#ifndef MQ1_CHAR_LEN_TIMESTAMP +#define MQ1_CHAR_LEN_TIMESTAMP 27 +#endif + +#ifndef MQ1_FLOAT_LEN_THRESHOLD +#define MQ1_FLOAT_LEN_THRESHOLD 8 +#endif + +#ifndef MQ1_CHAR_LEN_HEADER_EXTENSION_ID +#define MQ1_CHAR_LEN_HEADER_EXTENSION_ID 5 +#endif + +#ifndef MQ1_CHAR_LEN_EXTENDED_TIMESTAMP +#define MQ1_CHAR_LEN_EXTENDED_TIMESTAMP 31 +#endif + +#ifndef MQ1_FIELDS_NUM_FIELDS +#define MQ1_FIELDS_NUM_FIELDS 19 +#endif + +#ifndef DAC_NUM_FIELDS +#define DAC_NUM_FIELDS 28 +#endif diff --git a/src/mib_header.h b/src/mib_header.h new file mode 100644 index 0000000..f458347 --- /dev/null +++ b/src/mib_header.h @@ -0,0 +1,115 @@ +// clang-format Language: C +#include "macros.h" +#ifndef MIB_HEADER_H +#define MIB_HEADER_H + +typedef struct { + char dac_format[4]; + unsigned int threshold0; + unsigned int threshold1; + unsigned int threshold2; + unsigned int threshold3; + unsigned int threshold4; + unsigned int threshold5; + unsigned int threshold6; + unsigned int threshold7; + unsigned int preamp; + unsigned int ikrum; + unsigned int shaper; + unsigned int disc; + unsigned int disc_LS; + unsigned int shaper_test; + unsigned int dac_disc_L; + unsigned int dac_test; + unsigned int dac_disc_H; + unsigned int delay; + unsigned int TP_buff_in; + unsigned int TP_buff_out; + unsigned int RPZ; + unsigned int GND; + unsigned int TP_ref; + unsigned int FBK; + unsigned int Cas; + unsigned int TP_ref_A; + unsigned int TP_ref_B; +} dac_rx; + +/* +field 1: header ID (MQ1) +field 2: sequence number of a frame +field 3: the number of bytes of the header +field 4: the number of chips +field 5: the number of columns of the detector (x) +field 6: the number of rows of the detector (y) +field 7: the pixel data type (U01, U08, U16, U32, U64) +field 8: sensor layout (2x2, Nx1, 2x2G, Nx1G, with leading spaces) +field 9: active chip(s) during the capture of the frame, U8 hexadecimal repr +field 10: timestamp +field 11: shutter opening time (seconds) +field 12: counter 0 or 1 +field 13: colour mode, 0=monochrome image, 1=colour image +field 14: gain modem 0 = SLGM, 1 = LGM, 2 = HGM, 3 = SHGM +field 15-22: threshold values (keV) + +DAC of each chips contains 28 entries. + +Header extension + Single / Quad +field 51 / 135 : MQ1A +field 52 / 136 : UTC timestamp (time in ns) +field 53 / 137 : shutter opening time (with suffix "ns") +field 54 / 138 : the pixel data bit depth + +The remainings are null bytes for padding. +*/ + +typedef struct { + char header_id[MQ1_CHAR_LEN_HEADER_ID]; + unsigned int sequence_number; + unsigned int header_bytes; + unsigned int num_chips; + unsigned int det_x; + unsigned int det_y; + char pixel_depth[MQ1_CHAR_LEN_PIXEL_DEPTH]; + char sensor_layout[MQ1_CHAR_LEN_SENSOR_LAYOUT]; + char chip_select[MQ1_CHAR_LEN_CHIP_SELECT]; + char timestamp[MQ1_CHAR_LEN_TIMESTAMP]; + double exposure_time_s; + unsigned int counter; + unsigned int colour_mode; + unsigned int gain_mode; + float threshold[MQ1_FLOAT_LEN_THRESHOLD]; + dac_rx dac0; + char header_extension_id[MQ1_CHAR_LEN_HEADER_EXTENSION_ID]; + char extended_timestamp[MQ1_CHAR_LEN_EXTENDED_TIMESTAMP]; + unsigned int exposure_time_ns; + unsigned int bit_depth; +} mq1s; + +typedef struct { + char header_id[MQ1_CHAR_LEN_HEADER_ID]; + unsigned int sequence_number; + unsigned int header_bytes; + unsigned int num_chips; + unsigned int det_x; + unsigned int det_y; + char pixel_depth[MQ1_CHAR_LEN_PIXEL_DEPTH]; + char sensor_layout[MQ1_CHAR_LEN_SENSOR_LAYOUT]; + char chip_select[MQ1_CHAR_LEN_CHIP_SELECT]; + char timestamp[MQ1_CHAR_LEN_TIMESTAMP]; + double exposure_time_s; + unsigned int counter; + unsigned int colour_mode; + unsigned int gain_mode; + float threshold[MQ1_FLOAT_LEN_THRESHOLD]; + dac_rx dac0; + dac_rx dac1; + dac_rx dac2; + dac_rx dac3; + char header_extension_id[MQ1_CHAR_LEN_HEADER_EXTENSION_ID]; + char extended_timestamp[MQ1_CHAR_LEN_EXTENDED_TIMESTAMP]; + unsigned int exposure_time_ns; + unsigned int bit_depth; +} mq1q; + +#endif diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..8b59df2 --- /dev/null +++ b/src/parser.h @@ -0,0 +1,13 @@ +// clang-format Language: C +#include "mib_header.h" + +#ifndef PARSER_H +#define PARSER_H +void parse_mq1_single(const char *header, mq1s *mq1_single); + +void print_single_mib_header(mq1s header); + +void parse_mq1_quad(const char *header, mq1q *mq1_quad); + +void print_quad_mib_header(mq1q header); +#endif diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..7105499 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,18 @@ +// clang-format Language: C +#include + +#ifndef UTILS_H +#define UTILS_H + +const char *only_file_name(const char *absolute_file_path); + +unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride); + +void header_meta_from_first(FILE *mib_ptr, + char *header_id, + unsigned int *header_bytes, + unsigned int *num_chips, + unsigned int *det_x, + unsigned int *det_y, + char *pixel_depth); +#endif From ee13830cf4a2b247700e402407d4dd919c4091ef Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 13:32:41 +0100 Subject: [PATCH 029/251] Change header guard for macros.h --- src/macros.h | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/src/macros.h b/src/macros.h index 0b79839..81d97ae 100644 --- a/src/macros.h +++ b/src/macros.h @@ -1,56 +1,32 @@ // clang-format Language: C -#ifndef MQ1_SINGLE_HEADER_BYTES +#ifndef MACROS_H +#define MACROS_H + #define MQ1_SINGLE_HEADER_BYTES 384 -#endif -#ifndef MQ1_SINGLE_HEADER_NUM_FIELDS #define MQ1_SINGLE_HEADER_NUM_FIELDS 54 -#endif -#ifndef MQ1_QUAD_HEADER_BYTES #define MQ1_QUAD_HEADER_BYTES 768 -#endif -#ifndef MQ1_QUAD_HEADER_NUM_FIELDS #define MQ1_QUAD_HEADER_NUM_FIELDS 138 -#endif -#ifndef MQ1_CHAR_LEN_HEADER_ID #define MQ1_CHAR_LEN_HEADER_ID 4 -#endif -#ifndef MQ1_CHAR_LEN_PIXEL_DEPTH #define MQ1_CHAR_LEN_PIXEL_DEPTH 4 -#endif -#ifndef MQ1_CHAR_LEN_SENSOR_LAYOUT #define MQ1_CHAR_LEN_SENSOR_LAYOUT 7 -#endif -#ifndef MQ1_CHAR_LEN_CHIP_SELECT #define MQ1_CHAR_LEN_CHIP_SELECT 3 -#endif -#ifndef MQ1_CHAR_LEN_TIMESTAMP #define MQ1_CHAR_LEN_TIMESTAMP 27 -#endif -#ifndef MQ1_FLOAT_LEN_THRESHOLD #define MQ1_FLOAT_LEN_THRESHOLD 8 -#endif -#ifndef MQ1_CHAR_LEN_HEADER_EXTENSION_ID #define MQ1_CHAR_LEN_HEADER_EXTENSION_ID 5 -#endif -#ifndef MQ1_CHAR_LEN_EXTENDED_TIMESTAMP #define MQ1_CHAR_LEN_EXTENDED_TIMESTAMP 31 -#endif -#ifndef MQ1_FIELDS_NUM_FIELDS #define MQ1_FIELDS_NUM_FIELDS 19 -#endif -#ifndef DAC_NUM_FIELDS #define DAC_NUM_FIELDS 28 #endif From fe162a6529973caa7595b4e7e7d446f2febc2649 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 14:05:46 +0100 Subject: [PATCH 030/251] resolve conflict in clang-format-check.yml with dev branch --- .github/workflows/clang-format-check.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 0eb8971..0619f0b 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -11,10 +11,15 @@ jobs: formatting-check: runs-on: ubuntu-latest name: Formatting Check + strategy: + matrix: + path: + - 'src' + - 'include' steps: - uses: actions/checkout@v4 - name: Run clang-format style check uses: jidicula/clang-format-action@v4.15.0 with: clang-format-version: '20' - check-path: 'src' + check-path: ${{ matrix.path }} From d2eafde1f2b04df8be11c87fcb4a1e2d41fec5a6 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 14:27:55 +0100 Subject: [PATCH 031/251] Change formatting using clang-format --- src/framebuffer.c | 16 ++++++++-------- src/framebuffer.h | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index ef791c5..eb760b4 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -111,8 +111,8 @@ void allocate_frame_data(framebuffer *fb) fprintf(stderr, "malloc failed for data in read_frame"); return; } - fb->data = data - for (int i = 0; i < (int) dety; i++) { + fb->data = data for (int i = 0; i < (int) dety; i++) + { buffer[i] = (uint64_t *) data + i * detx; } break; @@ -130,12 +130,12 @@ void allocate_frame_data(framebuffer *fb) * The function will return the size of the data after compression * which is from blosc_compress_ctx */ -int compress_frame(framebuffer fb*, - unsigned int compression_level, - unsigned int shuffle, - char *compressor, - size_t blocksize, - int numinternalthreads) +int compress_frame(framebuffer fb *, + unsigned int compression_level, + unsigned int shuffle, + char *compressor, + size_t blocksize, + int numinternalthreads) { int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + (fb->mq1_header->pixel_depth[2] - '0'); diff --git a/src/framebuffer.h b/src/framebuffer.h index efff8b5..50574b3 100644 --- a/src/framebuffer.h +++ b/src/framebuffer.h @@ -25,11 +25,11 @@ void allocate_frame_data(framebuffer *fb); // compress data inside framebuffer int compress_frame(framebuffer *fb, - unsigned int compression_level, - unsigned int shuffle, - char *compressor, - size_t blocksize, - int numinternalthreads); + unsigned int compression_level, + unsigned int shuffle, + char *compressor, + size_t blocksize, + int numinternalthreads); // this is responsible for freeing the whole struct void deallocate_frame(framebuffer *fb); From f40e432cebb28a28a658792b6612b876a6ad08a9 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 14:51:03 +0100 Subject: [PATCH 032/251] Add files for initializing hdf5 --- src/hdf5_init.c | 177 ++++++++++++++++++++++++++ src/hdf5_init.h | 32 +++++ src/hdf5_init_meta.c | 294 +++++++++++++++++++++++++++++++++++++++++++ src/hdf5_init_meta.h | 23 ++++ 4 files changed, 526 insertions(+) create mode 100644 src/hdf5_init.c create mode 100644 src/hdf5_init.h create mode 100644 src/hdf5_init_meta.c create mode 100644 src/hdf5_init_meta.h diff --git a/src/hdf5_init.c b/src/hdf5_init.c new file mode 100644 index 0000000..0194f01 --- /dev/null +++ b/src/hdf5_init.c @@ -0,0 +1,177 @@ +#include "hdf5_init.h" +#include "blosc_filter.h" + +#include +#include +#include +#include +#include +#include + +/* +// functions for debugging +void check_space_and_storage(hid_t dset) { + H5D_space_status_t space_status; + hsize_t storage_size; + + status = H5Dget_space_status(dset, &space_status); + storage_size = H5Dget_storage_size(dset); + printf("Space for dataset has%sbeen allocated. \n", space_status == +H5D_SPACE_STATUS_ALLOCATED ? " " : " NOT "); printf("Storage size for dataset is +: %ld bytes.\n", (long)storage_size); +} +*/ + +// REAL functions +void initialize_file_and_plist(char *filename, + hid_t *file_id, + hid_t *fapl_id, + hid_t *fcpl_id) +{ + unsigned mode = H5F_ACC_TRUNC; + char *version, *date; + + if ((*fcpl_id = H5Pcreate(H5P_FILE_CREATE)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating fcpl in create_file\n"); + return; + } + if ((*fapl_id = H5Pcreate(H5P_FILE_ACCESS)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating fapl in create_file\n"); + return; + } else { + if (H5Pset_alignment(*fapl_id, 1024, 4096) < 0) { + fprintf(stderr, "Error in H5Pset_alignment\n"); + return; + } + } + if ((*file_id = H5Fcreate(filename, mode, *fcpl_id, *fapl_id)) == + H5I_INVALID_HID) { + fprintf(stderr, "Error in creating file_id in create_file, please check if " + "file already existed\n"); + return; + } + if (register_blosc(&version, &date) < 0) { + fprintf(stderr, "Error in register_blosc\n"); + return; + } else { + printf("Blosc version info: %s (%s)\n", version, date); + free(version); + free(date); + } +} + +void initialize_lcpl(hid_t *lcpl_id) +{ + if ((*lcpl_id = H5Pcreate(H5P_LINK_CREATE)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating lcpl in initialize_dataset_plist\n"); + return; + } + /* + else { + if (H5Pset_create_intermediate_group(*lcpl_id, 1) < 0) { + fprintf(stderr, "Error in H5Pset_create_intermediate_group\n"); + return; + } + if (H5Pset_char_encoding(*lcpl_id, H5T_CSET_UTF8) < 0) { + fprintf(stderr, "Error in H5Pset_char_encoding\n"); + return; + } + } + */ +} + +void create_merlin_dataset(hid_t *merlin_dataset_id, + hid_t *file_id, + char *merlin_dataset_name, + int dtype, + hid_t memspace, + hid_t *lcpl_id, + size_t dim, + hsize_t *frame_dim, + unsigned int compression_level, + unsigned int shuffle, + unsigned int compressor) +{ + hid_t file = *file_id; + hid_t lcpl = *lcpl_id; + hid_t dcpl; + hid_t dapl; + // int fill_value = -1; + unsigned int cd_values[7] = {0}; + + if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating dcpl\n"); + return; + } else { + if (H5Pset_chunk(dcpl, dim, frame_dim) < 0) { + fprintf(stderr, "Error in H5Pset_chunk\n"); + return; + } + if (H5Pset_fill_time(dcpl, H5D_FILL_TIME_NEVER) < 0) { + fprintf(stderr, "Error in H5Pset_fill_time\n"); + return; + } + /* + if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fill_value) < 0) { + fprintf(stderr, "Error in H5Pset_fill_value\n"); + return; + } + */ + cd_values[0] = 0; + cd_values[1] = compression_level; + cd_values[2] = shuffle; + cd_values[3] = 0; // blocksize + cd_values[4] = 0; // unused + cd_values[5] = 0; // unused + cd_values[6] = compressor; + if (H5Pset_filter(dcpl, FILTER_BLOSC, H5Z_FLAG_OPTIONAL, 7, cd_values) < + 0) { + fprintf(stderr, "Error in H5Pset_filter\n"); + return; + } + } + + if ((dapl = H5Pcreate(H5P_DATASET_ACCESS)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating dapl_id\n"); + return; + } else { + unsigned int y = frame_dim[1]; + unsigned int x = frame_dim[2]; + + if (H5Pset_chunk_cache(dapl, 521, 2 * dtype * y * x, 1.0) < 0) { + fprintf(stderr, "Error in H5Pset)chunk_cache\n"); + return; + } + } + + hid_t datatype; + switch (dtype) { + case 1: { + datatype = H5T_STD_U8LE; + break; + } + case 2: { + datatype = H5T_STD_U16LE; + break; + } + case 4: { + datatype = H5T_STD_U32LE; + break; + } + case 8: { + datatype = H5T_STD_U64LE; + break; + } + default: { + fprintf(stderr, "Error in datatype, please check input dtype\n"); + return; + } + } + + if ((*merlin_dataset_id = H5Dcreate2(file, merlin_dataset_name, datatype, + memspace, lcpl, dcpl, dapl)) == + H5I_INVALID_HID) { + fprintf(stderr, "Error in creating merlin_dataset\n"); + return; + } +} diff --git a/src/hdf5_init.h b/src/hdf5_init.h new file mode 100644 index 0000000..6b917e5 --- /dev/null +++ b/src/hdf5_init.h @@ -0,0 +1,32 @@ +// clang-format Language: C +#ifndef HDF5_INIT_H +#define HDF5_INIT_H + +#include +#include +#include +#include +#include + +void check_space_and_storage(hid_t dset); + +void initialize_file_and_plist(char *filename, + hid_t *file_id, + hid_t *fapl_id, + hid_t *fcpl_id); + +void initialize_lcpl(hid_t *lcpl_id); + +void create_merlin_dataset(hid_t *merlin_dataset_id, + hid_t *file_id, + char *merlin_dataset_name, + int dtype, + hid_t memspace, + hid_t *lcpl_id, + size_t dim, + hsize_t *frame_dim, + unsigned int compression_level, + unsigned int shuffle, + unsigned int compressor); + +#endif diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c new file mode 100644 index 0000000..016a925 --- /dev/null +++ b/src/hdf5_init_meta.c @@ -0,0 +1,294 @@ +#include "hdf5_init_meta.h" +#include "macros.h" + +#include +#include +#include +#include +#include + +void create_meta_mq1_fields_dataset(hid_t *file_id, + hid_t *lcpl_id, + hid_t *meta_handle) +{ + if (meta_handle == NULL) { + fprintf(stderr, "meta_handle is NULL in create_meta_fields_dataset\n"); + return; + } + + hid_t file = *file_id; + hid_t lcpl = *lcpl_id; + + char meta_group_path[64] = "metadata"; + hid_t meta_group = + H5Gcreate(file, meta_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); + if (meta_group < 0) { + fprintf(stderr, "Error creating group in create_meta_mq1_fields_dataset\n"); + return; + } + + hsize_t dim[1] = {0}; + hsize_t max_dim[1] = {H5S_UNLIMITED}; + hsize_t chunk_dim[1] = {1}; + + hid_t dataspace = H5Screate_simple(1, dim, max_dim); + if (dataspace < 0) { + fprintf(stderr, + "Error creating dataspace in create_meta_mq1_fields_dataset\n"); + return; + } + + hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); + if (dcpl < 0) { + fprintf(stderr, "Error creating dcpl in create_meta_mq1_fields_dataset\n"); + H5Sclose(dataspace); + H5Gclose(meta_group); + return; + } else { + if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { + fprintf(stderr, + "Error setting chunking in create_meta_mq1_fields_dataset\n"); + H5Pclose(dcpl); + H5Sclose(dataspace); + H5Gclose(meta_group); + return; + } + } + + hid_t dapl = H5Pcreate(H5P_DATASET_ACCESS); + if (dapl < 0) { + fprintf(stderr, + "Error in creating dapl in create_meta_mq1_fields_dataset\n"); + H5Pclose(dcpl); + H5Sclose(dataspace); + H5Gclose(meta_group); + return; + } else { + } + + // hid_t header_id_type = H5Tcopy(H5T_C_S1); + // H5Tset_size(header_id_type, MQ1_CHAR_LEN_HEADER_ID); + + hid_t pixel_depth_type = H5Tcopy(H5T_C_S1); + H5Tset_size(pixel_depth_type, MQ1_CHAR_LEN_PIXEL_DEPTH); + + hid_t sensor_layout_type = H5Tcopy(H5T_C_S1); + H5Tset_size(sensor_layout_type, MQ1_CHAR_LEN_SENSOR_LAYOUT); + + hid_t chip_select_type = H5Tcopy(H5T_C_S1); + H5Tset_size(chip_select_type, MQ1_CHAR_LEN_CHIP_SELECT); + + hid_t timestamp_type = H5Tcopy(H5T_C_S1); + H5Tset_size(timestamp_type, MQ1_CHAR_LEN_TIMESTAMP); + + hid_t header_extension_id_type = H5Tcopy(H5T_C_S1); + H5Tset_size(header_extension_id_type, MQ1_CHAR_LEN_HEADER_EXTENSION_ID); + + hid_t extended_timestamp_type = H5Tcopy(H5T_C_S1); + H5Tset_size(extended_timestamp_type, MQ1_CHAR_LEN_EXTENDED_TIMESTAMP); + + hsize_t threshold_dims[1] = {MQ1_FLOAT_LEN_THRESHOLD}; + hid_t threshold_type = H5Tarray_create(H5T_NATIVE_FLOAT, 1, threshold_dims); + + struct { + const char *name; + hid_t type; + } fields[] = { + //{"header_id", header_id_type}, + {"max_length", H5T_NATIVE_UINT}, + {"sequence_number", H5T_NATIVE_UINT}, + {"header_bytes", H5T_NATIVE_UINT}, + {"num_chips", H5T_NATIVE_UINT}, + {"det_x", H5T_NATIVE_UINT}, + {"det_y", H5T_NATIVE_UINT}, + {"pixel_depth", pixel_depth_type}, + {"sensor_layout", sensor_layout_type}, + {"chip_select", chip_select_type}, + {"timestamp", timestamp_type}, + {"exposure_time_s", H5T_NATIVE_DOUBLE}, + {"counter", H5T_NATIVE_UINT}, + {"colour_mode", H5T_NATIVE_UINT}, + {"gain_mode", H5T_NATIVE_UINT}, + {"threshold", threshold_type}, + {"header_extension_id", header_extension_id_type}, + {"extended_timestamp", extended_timestamp_type}, + {"exposure_time_ns", H5T_NATIVE_UINT}, + {"bit_depth", H5T_NATIVE_UINT}, + }; + + size_t num_datasets = sizeof(fields) / sizeof(fields[0]); + + for (size_t i = 0; i < num_datasets; i++) { + char dataset_path[256]; + // snprintf(dataset_path, sizeof(dataset_path), "metadata/%s", + // fields[i].name); + + snprintf(dataset_path, sizeof(dataset_path), "%s", fields[i].name); + + hid_t dataset = H5Dcreate2(meta_group, dataset_path, fields[i].type, + dataspace, lcpl, dcpl, dapl); + if (dataset < 0) { + fprintf(stderr, "Error creating dataset : %s\n", dataset_path); + meta_handle[i] = -1; + continue; + } + + meta_handle[i] = dataset; + } + + // H5Tclose(header_id_type); + H5Tclose(pixel_depth_type); + H5Tclose(sensor_layout_type); + H5Tclose(chip_select_type); + H5Tclose(timestamp_type); + H5Tclose(header_extension_id_type); + H5Tclose(extended_timestamp_type); + H5Tclose(threshold_type); + + H5Pclose(dcpl); + H5Pclose(dapl); + H5Sclose(dataspace); + H5Gclose(meta_group); +} + +void create_dac_dataset(unsigned int num_chips, + hid_t *file_id, + hid_t *lcpl_id, + hid_t *dac_handle) +{ + if (dac_handle == NULL) { + fprintf(stderr, "dac_handle is NULL in create_dac_meta_dataset\n"); + return; + } + + hid_t file = *file_id; + hid_t lcpl; + if (lcpl_id == NULL) { + lcpl = H5P_DEFAULT; + } else { + lcpl = *lcpl_id; + } + char chip_group_path[256]; + char dataset_path[512]; + hid_t chip_group; + hsize_t dim[1] = {0}; + hsize_t max_dim[1] = {H5S_UNLIMITED}; + hsize_t chunk_dim[1] = {1}; + hid_t dataspace; + hid_t dataset; + + hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); + if (dcpl < 0) { + fprintf(stderr, "Error creating dcpl in create_dac_dataset\n"); + return; + } else { + if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { + fprintf(stderr, "Error setting chunking in create_dac_dataset\n"); + H5Pclose(dcpl); + return; + } + } + + hid_t dapl = H5Pcreate(H5P_DATASET_ACCESS); + if (dapl < 0) { + fprintf(stderr, "Error creating dapl in create_dac_dataset\n"); + H5Pclose(dcpl); + return; + } else { + // modify dapl if needed + } + + hid_t str_type = H5Tcopy(H5T_C_S1); + if (H5Tset_size(str_type, 4) < 0) { + fprintf(stderr, "Error setting string type size in create_dac_dataset\n"); + H5Tclose(str_type); + H5Pclose(dcpl); + H5Pclose(dapl); + return; + } + + struct { + const char *name; + hid_t type; + } datasets[] = { + {"dac_format", str_type}, {"threshold0", H5T_NATIVE_UINT}, + {"threshold1", H5T_NATIVE_UINT}, {"threshold2", H5T_NATIVE_UINT}, + {"threshold3", H5T_NATIVE_UINT}, {"threshold4", H5T_NATIVE_UINT}, + {"threshold5", H5T_NATIVE_UINT}, {"threshold6", H5T_NATIVE_UINT}, + {"threshold7", H5T_NATIVE_UINT}, {"preamp", H5T_NATIVE_UINT}, + {"ikrum", H5T_NATIVE_UINT}, {"shaper", H5T_NATIVE_UINT}, + {"disc", H5T_NATIVE_UINT}, {"disc_LS", H5T_NATIVE_UINT}, + {"shaper_test", H5T_NATIVE_UINT}, {"dac_disc_L", H5T_NATIVE_UINT}, + {"dac_test", H5T_NATIVE_UINT}, {"dac_disc_H", H5T_NATIVE_UINT}, + {"delay", H5T_NATIVE_UINT}, {"TP_buff_in", H5T_NATIVE_UINT}, + {"TP_buff_out", H5T_NATIVE_UINT}, {"RPZ", H5T_NATIVE_UINT}, + {"GND", H5T_NATIVE_UINT}, {"TP_ref", H5T_NATIVE_UINT}, + {"FBK", H5T_NATIVE_UINT}, {"Cas", H5T_NATIVE_UINT}, + {"TP_ref_A", H5T_NATIVE_UINT}, {"TP_ref_B", H5T_NATIVE_UINT}}; + + size_t num_datasets = sizeof(datasets) / sizeof(datasets[0]); + int handle_pos = 0; + + for (unsigned int i = 0; i < num_chips; i++) { + snprintf(chip_group_path, sizeof(chip_group_path), "metadata/Chip%02d", i); + + chip_group = + H5Gcreate(file, chip_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); + if (chip_group < 0) { + fprintf(stderr, "Error creating group chip%02d in create_dac_dataset\n", + i); + H5Tclose(str_type); + H5Pclose(dcpl); + H5Pclose(dapl); + return; + } + + dataspace = H5Screate_simple(1, dim, max_dim); + if (dataspace < 0) { + fprintf(stderr, "Error creating dataspace in create_dac_meta_dataset\n"); + H5Tclose(str_type); + H5Pclose(dcpl); + H5Pclose(dapl); + H5Gclose(chip_group); + return; + } + + handle_pos = num_datasets * (size_t) i; + + for (size_t j = handle_pos; j < (handle_pos + num_datasets); j++) { + // snprintf(dataset_path, sizeof(dataset_path), "%s/%s", chip_group_path, + // datasets[j-handle_pos].name); + + snprintf(dataset_path, sizeof(dataset_path), "%s", + datasets[j - handle_pos].name); + + dataset = + H5Dcreate2(chip_group, dataset_path, datasets[j - handle_pos].type, + dataspace, lcpl, dcpl, dapl); + if (dataset < 0) { + fprintf(stderr, "Error creating dataset: %s\n", dataset_path); + dac_handle[j] = H5I_INVALID_HID; + continue; + } + dac_handle[j] = dataset; + } + + H5Sclose(dataspace); + H5Gclose(chip_group); + } + + H5Tclose(str_type); + H5Pclose(dcpl); + H5Pclose(dapl); +} + +void close_dataset_handle(hid_t *handle, size_t count) +{ + if (!handle) + return; + for (size_t i = 0; i < count; i++) { + if (handle[i] >= 0) { + H5Dclose(handle[i]); + } + } +} diff --git a/src/hdf5_init_meta.h b/src/hdf5_init_meta.h new file mode 100644 index 0000000..946f939 --- /dev/null +++ b/src/hdf5_init_meta.h @@ -0,0 +1,23 @@ +// clang-format Language: C +#ifndef HDF5_INIT_META_H +#define HDF5_INIT_META_H + +#include "macros.h" +#include +#include +#include +#include +#include + +void create_meta_mq1_fields_dataset(hid_t *file_id, + hid_t *lcpl_id, + hid_t *meta_handle); + +void create_dac_dataset(unsigned int num_chips, + hid_t *file_id, + hid_t *lcpl_id, + hid_t *dac_handle); + +void close_dataset_handle(hid_t *handle, size_t count); + +#endif From e4d924076331f240abacc5dfd5215fc35b8d71ea Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 16:26:26 +0100 Subject: [PATCH 033/251] Comment out debug functions in hdf5_init.h --- src/hdf5_init.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 6b917e5..f365b39 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -8,7 +8,7 @@ #include #include -void check_space_and_storage(hid_t dset); +// void check_space_and_storage(hid_t dset); void initialize_file_and_plist(char *filename, hid_t *file_id, From 8e41d214bc18609e2a4f83aa3ecca3c3517a2b8e Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 16:31:04 +0100 Subject: [PATCH 034/251] Add files for reading .mib files into framebuffer --- src/read.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/read.h | 16 ++++++ 2 files changed, 163 insertions(+) create mode 100644 src/read.c create mode 100644 src/read.h diff --git a/src/read.c b/src/read.c new file mode 100644 index 0000000..d82137c --- /dev/null +++ b/src/read.c @@ -0,0 +1,147 @@ +#include "read.h" +#include "framebuffer.h" +#include "io_header.h" +#include "macros.h" +#include "parser.h" +#include "utils.h" + +#include +#include +#include +#include +#include + +void read_header(FILE *mib_ptr, long offset, framebuffer *fb) +{ + fseek(mib_ptr, offset, SEEK_SET); + char buf[16] = {0}; + char headersize_str[6] = {0}; + fread(buf, sizeof(char), 16, mib_ptr); + memcpy(headersize_str, buf + 11, 5); + headersize_str[5] = '\0'; + int headersize = atoi(headersize_str); + char *header = malloc(sizeof(char) * headersize); + MQ1_fields *mq1_header = malloc(sizeof(MQ1_fields)); + if (!mq1_header) { + fprintf(stderr, "malloc fail for mq1_header in read_header\n"); + free(header); + header = NULL; + return; + } + *mq1_header = allocate_MQ1_fields(1); + fb->dac0 = (dac_rx *) malloc(sizeof(dac_rx)); + fb->dac1 = (dac_rx *) malloc(sizeof(dac_rx)); + fb->dac2 = (dac_rx *) malloc(sizeof(dac_rx)); + fb->dac3 = (dac_rx *) malloc(sizeof(dac_rx)); + + fseek(mib_ptr, offset, SEEK_SET); + fread(header, sizeof(char), headersize, mib_ptr); + + switch (headersize) { + case 384: { + mq1s mq1_single; + parse_mq1_single(header, &mq1_single); + memcpy(fb->dac0, &mq1_single.dac0, sizeof(dac_rx)); + fb->dac1 = NULL; + fb->dac2 = NULL; + fb->dac3 = NULL; + fill_MQ1_single_fields(mq1_header, 0, mq1_single); + fb->mq1_header = mq1_header; + break; + } + case 768: { + mq1q mq1_quad; + parse_mq1_quad(header, &mq1_quad); + memcpy(fb->dac0, &mq1_quad.dac0, sizeof(dac_rx)); + memcpy(fb->dac1, &mq1_quad.dac1, sizeof(dac_rx)); + memcpy(fb->dac2, &mq1_quad.dac2, sizeof(dac_rx)); + memcpy(fb->dac3, &mq1_quad.dac3, sizeof(dac_rx)); + fill_MQ1_quad_fields(mq1_header, 0, mq1_quad); + fb->mq1_header = mq1_header; + break; + } + default: { + deallocate_MQ1_fields(*mq1_header); + free(header); + header = NULL; + free(mq1_header); + mq1_header = NULL; + fprintf(stderr, "headersize not 384 or 768\n"); + return; + } + } + free(header); + header = NULL; +} + +void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) +{ + if (!mib_ptr || !fb) { + fprintf(stderr, "Missing input in read_frame\n"); + if (!mib_ptr) + fprintf(stderr, "NO MIB_PTR\n"); + if (!fb) + fprintf(stderr, "NO fb\n"); + return; + } + + int headersize = *(fb->mq1_header->header_bytes); + + int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + + (fb->mq1_header->pixel_depth[2] - '0'); + bufsize = bufsize / 8; + + int detx = (int) *(fb->mq1_header->det_x); + int dety = (int) *(fb->mq1_header->det_y); + + // move mib_ptr to the correct place + fseek(mib_ptr, offset + headersize, SEEK_SET); + + // write data into buffer + uint8_t *raw_data = malloc(bufsize * detx * dety); + if (!raw_data) { + fprintf(stderr, "malloc failed for raw_data in read_frame\n"); + return; + } + + // TO-DO: add checks for corruption + fread(raw_data, sizeof(char), bufsize * detx * dety, mib_ptr); + + for (int i = 0; i < dety; i++) { + for (int j = 0; j < detx; j++) { + size_t index = (i * detx + j) * bufsize; + uint8_t *raw_bytes = &raw_data[index]; + uint64_t value = 0; + + switch (bufsize) { + case 1: { + value = raw_bytes[0]; + ((uint8_t **) fb->rows)[i][j] = (uint8_t) value; + break; + } + case 2: { + value = (raw_bytes[0] << 8) | raw_bytes[1]; + ((uint16_t **) fb->rows)[i][j] = (uint16_t) value; + break; + } + case 4: { + value = (raw_bytes[0] << 24) | (raw_bytes[1] << 16) | + (raw_bytes[2] << 8) | raw_bytes[3]; + ((uint32_t **) fb->rows)[i][j] = (uint32_t) value; + break; + } + case 8: { + value = + ((uint64_t) raw_bytes[0] << 56) | ((uint64_t) raw_bytes[1] << 48) | + ((uint64_t) raw_bytes[2] << 40) | ((uint64_t) raw_bytes[3] << 32) | + ((uint64_t) raw_bytes[4] << 24) | ((uint64_t) raw_bytes[5] << 16) | + ((uint64_t) raw_bytes[6] << 8) | ((uint64_t) raw_bytes[7]); + ((uint64_t **) fb->rows)[i][j] = value; + break; + } + } + } + } + free(raw_data); + raw_data = NULL; +} diff --git a/src/read.h b/src/read.h new file mode 100644 index 0000000..49a159c --- /dev/null +++ b/src/read.h @@ -0,0 +1,16 @@ +// clang-format Language: C +#ifndef READ_H +#define READ_H + +#include "framebuffer.h" +#include "io_header.h" +#include "macros.h" +#include "parser.h" +#include "utils.h" +#include + +void read_header(FILE *mib_ptr, long offset, framebuffer *fb); + +void read_frame(FILE *mib_ptr, long offset, framebuffer *fb); + +#endif From bc67db717c9c066b7277378a04b6d32435c564d5 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 16:37:27 +0100 Subject: [PATCH 035/251] Remove duplicate malloc for framebuffer --- src/read.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/read.c b/src/read.c index d82137c..29c58b6 100644 --- a/src/read.c +++ b/src/read.c @@ -21,18 +21,6 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) headersize_str[5] = '\0'; int headersize = atoi(headersize_str); char *header = malloc(sizeof(char) * headersize); - MQ1_fields *mq1_header = malloc(sizeof(MQ1_fields)); - if (!mq1_header) { - fprintf(stderr, "malloc fail for mq1_header in read_header\n"); - free(header); - header = NULL; - return; - } - *mq1_header = allocate_MQ1_fields(1); - fb->dac0 = (dac_rx *) malloc(sizeof(dac_rx)); - fb->dac1 = (dac_rx *) malloc(sizeof(dac_rx)); - fb->dac2 = (dac_rx *) malloc(sizeof(dac_rx)); - fb->dac3 = (dac_rx *) malloc(sizeof(dac_rx)); fseek(mib_ptr, offset, SEEK_SET); fread(header, sizeof(char), headersize, mib_ptr); From 97465e8ec9d8271348d72880dde3e3457339be1b Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 17:01:07 +0100 Subject: [PATCH 036/251] Change Format according to clang-format --- src/read.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/read.c b/src/read.c index 29c58b6..a63777c 100644 --- a/src/read.c +++ b/src/read.c @@ -18,9 +18,9 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) char headersize_str[6] = {0}; fread(buf, sizeof(char), 16, mib_ptr); memcpy(headersize_str, buf + 11, 5); - headersize_str[5] = '\0'; - int headersize = atoi(headersize_str); - char *header = malloc(sizeof(char) * headersize); + headersize_str[5] = '\0'; + int headersize = atoi(headersize_str); + char *header = malloc(sizeof(char) * headersize); fseek(mib_ptr, offset, SEEK_SET); fread(header, sizeof(char), headersize, mib_ptr); From 599102c88e82827efa0e7bd38c1343116a1561aa Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 10:50:21 +0100 Subject: [PATCH 037/251] Remove extra mq1_header allocation in framebuffer.c --- src/framebuffer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index eb760b4..d6253db 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -34,8 +34,7 @@ void allocate_frame_header(framebuffer *fb) fprintf(stderr, "Error in malloc for dac0 in allocate_frame_header\n"); return; } - fb->mq1_header = allocate_MQ1_fields(1); - fb->dac1 = (dac_rx *) malloc(sizeof(dac_rx)); + fb->dac1 = (dac_rx *) malloc(sizeof(dac_rx)); if (!fb->dac1) { fprintf(stderr, "Error in malloc for dac1 in allocate_frame_header\n"); return; From 8eef264b66bbf9b615d4cb46c0305a9b139fa29d Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 10:53:54 +0100 Subject: [PATCH 038/251] Fix typo in framebuffer.c --- src/framebuffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index d6253db..0175724 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -65,8 +65,8 @@ void allocate_frame_data(framebuffer *fb) fprintf(stderr, "Error in malloc for fb->rows in allocate_frame_data\n"); return; } - void *data - NULL; - fb->rows = buffer; + void *data = NULL; + fb->rows = buffer; switch (bufsize) { case 1: { data = malloc(sizeof(uint8_t) * detx * dety); @@ -110,8 +110,8 @@ void allocate_frame_data(framebuffer *fb) fprintf(stderr, "malloc failed for data in read_frame"); return; } - fb->data = data for (int i = 0; i < (int) dety; i++) - { + fb->data = data; + for (int i = 0; i < (int) dety; i++) { buffer[i] = (uint64_t *) data + i * detx; } break; @@ -203,7 +203,7 @@ void deallocate_frame(framebuffer *fb) if (fb->dac3) free(fb->dac3); if (fb->mq1_header) { - deallocate_MQ1_fields(fb->mq1_header); + deallocate_MQ1_fields(*(fb->mq1_header)); free(fb->mq1_header); fb->mq1_header = NULL; } From 5361a2e0171b65e1bd745df1df550e401d044266 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 11:01:58 +0100 Subject: [PATCH 039/251] Fix bugs due to messing up clang-format, pre-commit and git --- src/framebuffer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index 0175724..0f98bc8 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -15,6 +15,7 @@ #include "framebuffer.h" #include "macros.h" #include "utils.h" +#include #include #include #include @@ -28,8 +29,8 @@ void allocate_frame_header(framebuffer *fb) "Error in malloc for mq1_header in allocate_frame_header\n"); return; } - fb->mq1_header = allocate_MQ1_fields(1); - fb->dac0 = (dac_rx *) malloc(sizeof(dac_rx)); + *(fb->mq1_header) = allocate_MQ1_fields(1); + fb->dac0 = (dac_rx *) malloc(sizeof(dac_rx)); if (!fb->dac0) { fprintf(stderr, "Error in malloc for dac0 in allocate_frame_header\n"); return; @@ -129,7 +130,7 @@ void allocate_frame_data(framebuffer *fb) * The function will return the size of the data after compression * which is from blosc_compress_ctx */ -int compress_frame(framebuffer fb *, +int compress_frame(framebuffer *fb, unsigned int compression_level, unsigned int shuffle, char *compressor, From d59d378463a7d58fb573adaba108e601f4111ed4 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 12:00:00 +0100 Subject: [PATCH 040/251] Fix typo in frambuffer --- src/framebuffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index 0f98bc8..f065d36 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -1,4 +1,4 @@ -/* These are the memory allocation functions of he struct framebuffer declared +/* These are functions of the struct framebuffer declared * in framebuffer.h * * allocate_frame_header only allocates mq1_header and dacs in framebuffer @@ -13,8 +13,11 @@ */ #include "framebuffer.h" +#include "io_header.h" #include "macros.h" +#include "mib_header.h" #include "utils.h" + #include #include #include @@ -68,6 +71,7 @@ void allocate_frame_data(framebuffer *fb) } void *data = NULL; fb->rows = buffer; + switch (bufsize) { case 1: { data = malloc(sizeof(uint8_t) * detx * dety); @@ -126,10 +130,6 @@ void allocate_frame_data(framebuffer *fb) } } -/* This is to compress the data inside framebuffer->data - * The function will return the size of the data after compression - * which is from blosc_compress_ctx - */ int compress_frame(framebuffer *fb, unsigned int compression_level, unsigned int shuffle, From 7159c76233ddff9033a31af281cef0a746ba0a06 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 13:13:48 +0100 Subject: [PATCH 041/251] fix typo --- src/read.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/read.c b/src/read.c index a63777c..bb76b72 100644 --- a/src/read.c +++ b/src/read.c @@ -18,9 +18,17 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) char headersize_str[6] = {0}; fread(buf, sizeof(char), 16, mib_ptr); memcpy(headersize_str, buf + 11, 5); - headersize_str[5] = '\0'; - int headersize = atoi(headersize_str); - char *header = malloc(sizeof(char) * headersize); + headersize_str[5] = '\0'; + int headersize = atoi(headersize_str); + char *header = malloc(sizeof(char) * headersize); + MQ1_fields *mq1_header = malloc(sizeof(MQ1_fields)); + if (!mq1_header) { + fprintf(stderr, "malloc fail for mq1_header in read_header\n"); + free(header); + header = NULL; + return; + } + *mq1_header = allocate_MQ1_fields(1); fseek(mib_ptr, offset, SEEK_SET); fread(header, sizeof(char), headersize, mib_ptr); From 22c74c56890701082277972105fc2d4fc8ed9c73 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 24 Apr 2025 09:36:42 +0100 Subject: [PATCH 042/251] Revert "Add compress_frame" This reverts commit aa303efff4185c4a6074a46c1a2ea7d19190d70a. --- src/framebuffer.c | 57 ----------------------------------------------- 1 file changed, 57 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index f065d36..07173e8 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -8,8 +8,6 @@ * * Please also call deallocate_frame for freeing the memory. deallocate_frame * frees both header and data - * - * compress_frame is used for compressing the data */ #include "framebuffer.h" @@ -130,61 +128,6 @@ void allocate_frame_data(framebuffer *fb) } } -int compress_frame(framebuffer *fb, - unsigned int compression_level, - unsigned int shuffle, - char *compressor, - size_t blocksize, - int numinternalthreads) -{ - int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + - (fb->mq1_header->pixel_depth[2] - '0'); - bufsize = bufsize / 8; - - int detx = (int) *(fb->mq1_header->det_x); - int dety = (int) *(fb->mq1_header->det_y); - - size_t nbytes = dety * detx * bufsize; - size_t destsize = nbytes + BLOSC_MAX_OVERHEAD; - void *dest = malloc(destsize); - if (!dest) { - fprintf(stderr, "Error in malloc for dest\n"); - return -1; - } - - int cbytes = blosc_compress_ctx(compression_level, shuffle, bufsize, nbytes, - fb->data, dest, destsize, compressor, - blocksize, numinternalthreads); - if (cbytes < 0) { - fprintf(stderr, "Error in blosc_compress\n"); - free(dest); - return -1; - } - if (cbytes == 0) { - fprintf(stderr, "Blosc returned 0 bytes (uncompressible?). Forcing " - "fallback to uncompressed write.\n"); - cbytes = nbytes; - return cbytes; - } - // for showing compression ratio in each frame, profiling purposes - // if (cbytes != 0) { - // printf("compression: %ld -> %d (%.1fx)\n", nbytes, cbytes, (1. * nbytes) / - // cbytes); - //} - - free(fb->data); - fb->data = malloc(destsize); - if (!fb->data) { - fprintf(stderr, "Error in malloc for fb->data\n"); - free(dest); - return -1; - } - - memcpy(fb->data, dest, cbytes); - free(dest); - return cbytes; -} - void deallocate_frame(framebuffer *fb) { if (fb == NULL) { From d558ce03fc40c1f82769e6925dc7d459da116f06 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 24 Apr 2025 09:38:20 +0100 Subject: [PATCH 043/251] Revert "Add compress_frame in framebuffer.h" This reverts commit 76ecde8008fbc65e0a85b4b3025a98b97be585a5. --- src/framebuffer.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/framebuffer.h b/src/framebuffer.h index 50574b3..084fe24 100644 --- a/src/framebuffer.h +++ b/src/framebuffer.h @@ -23,14 +23,6 @@ void allocate_frame_header(framebuffer *fb); // allocate memory for data in framebuffer void allocate_frame_data(framebuffer *fb); -// compress data inside framebuffer -int compress_frame(framebuffer *fb, - unsigned int compression_level, - unsigned int shuffle, - char *compressor, - size_t blocksize, - int numinternalthreads); - // this is responsible for freeing the whole struct void deallocate_frame(framebuffer *fb); From 28b99e794320f46cf2b2260c676eff6f3659566d Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 24 Apr 2025 09:39:21 +0100 Subject: [PATCH 044/251] Remove bin --- bin/main.out | Bin 112520 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 bin/main.out diff --git a/bin/main.out b/bin/main.out deleted file mode 100755 index b9751d80d27177c00dd388a9ef68ee7231653441..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112520 zcmeFa3wTu3)job^CPOZSBwU1usH1`niWsiOTb%#{g9eQPHbpQAxsYf`VlEh{NHoST zV;l`uY-+)#t+r|FC9TFUP=O$7qO~<%YSVtUO|7*P!LR8jwW*iR?|s+a=gdh+X#W4_ z`Ca;ydC1v&y?d>-*WP>W>$$MQm$BUGa2V##X?)Qj)iT{Hkh&U1_mdGGuaRcN8eZcZ z<7{IbxT5f9@_BX43}s}g!Ct}7*G z80YHnY=o&geg#7EoTlk?go|{15<)Njmg8><{_MZ;n(!c;XG=H*@n!g1g1^f&{skSL zhwv=?P1AIW4$s#igA4IDU(?fdc##e-MVO4gculjc3w3-k!ddw9;ctS*PDPlAzd87u zjlawBcQO7>^c$^hS*Ksrf|l#r6eZ|*tPP`&(r@DMcM1O3PSN<|kNs^j{>~tQ-PDbzZEtCzm796);r5ho1ZpjCC`ugc3j+) zI~=k8+BT*!Pu3^P#)K8pS`N8#sqJd*$Xd=&hmQS7{7lze|WO1>*c z(evmidN{U@Wanw4=y@J`CSn$Cc|He{hQT?CzYjI;8HTTgo#gi%&LNw{Ux+yIoMHSm z$Ttai_n{oJTfe(B-gY?0!WbE+^?MKJkhJs%5U2h=t;e);y0+6hEZI4%w}I|BN{GbPm&hP~$C!a}bO0r)c|g4(AZI^la6*F-*^88t)s1 z$C&mE!wszeit-B=amBYFHPy(@-n6-_G`q4Yx1uUL+wd>StSqR?&MT@ey%|JaQ9<6# z*;@)KDvQfXK`*!XvX^G8&R&+jCVjPU zP4?33eCca^*(;Z2Z$esGc>$FTWl3MU)VF%I$+9f3q^yz|te4=Z4gi%XK0rCq9OJI(b%kq`rADYFQ?5oq)ti0Zry>{i*YebiYEYG+m-Gn5! zd5g{L3QMXhi>OvrQ*K3eL1|uDesL)awkEftB6n-HGI_qqRajh7lD#Fjq?+a|+l1<^ zEYHm&u_D5`jQR>{stQW0$Q4P*R8cB3i)z_v8opYTN)2fp+4;qrDzP^7$@jY8B?o?I)LTmmPoE>&1% zLBY+&=7P2LO5f-ky}+(Y!sGP!0`)_J&n{IXmf6HsZm*~ zlfYeIWEbS;R^@_iV`Zh{0#urBtjJioWNG&Nx$_oU(Tl9u{JGpSIkCcb;HpA1?h=}) ziAVS%G0K?|3{~7jBb4Hb(i|qInQo^spy21g3BZ#WbIg6hgF7D@$6ZN4#zpMKii@#b zav2Y5x_WvswlGfP5zzb%9L$jrLO6?v{042fxi4X=IbL&*WbT(lN{?&AmkXdS9vja6 zg!%K@aPCpfUycpuzQg?0+HiA!!L$||Ztf$AciQl!1oW@ZhTHc=#^D^{p#5Hnsf*`u zjzoyt_m*B8&V7;j%Q>7QQS$pFrY^OIb0k81iNw^U<#3Kfh;uJx{*pU$B+9*+!vqm} zY&e?T`lZ-#mxbaSz=m_LYW~t}IP*4tUK>8n1QGgeIBhb2nKs;pbX zJY!&5kqtNZ|HR8}xVi5qUSq?}y*cq(8_u%<^VeX*&A!64CL3;FXEob!?&Hm0iw(D* znY7w)o{^ZpHXCl=`*+yzX(ltmP8*KZj`i!d;XL;+e?2zbJWpX-uMIcPeu($k@EHX3 zFJ!}cc3}PnY`A%r!L&geZk}z3%%L0!=p!D9sY{FvKg)(E+3>S%c(M&Y$A)`sIL}AS zUy2Q%Wr7G(ZTPu1Jk5rG!G?Qnc!~}8+wj>oJky5r{LB1h*>L;$SB?$m9@hL7*>Lmx zhiTvDlI|4xVbU(rZ9+dlnnPfJi_rIw=Fr#QB=nu6Ipp=%3cZaq z-MGJ8=nB#t;`(!hzKL`!=}e(FlIBp??-hC-X%2DysX|{znnPQ^N9Zd_b4cq?5_$<~ z4rTp@(3g z2pvb7Lsfs1&`#1EqWWuv{^Wb0IW+Z`3;jQ&IVAPx2>k(R4n_T$LcdFzLr}k0=wFlO z(9@qP^c$o(Brr!{HA88IP{R5w~{68k`A>AkR4@h$;>F*Kx z+oaDX-6{0Lq&al-w+a0KX$~3vEkfTznnOi@lhAjPK9_W@(A!9JXy`8&x`H%^g#H|% zZz4ULbf(Z7NplG3_X@p^G`oI(s?gVwW|!~x2z@1KcJ=-wp_h9hf8bqz-FpL>YgTr3 z8cklq-*u?zeg<9b1?Xp|ocEZ=IMzh|!-aDb&%6s7Fim!Jqa*t-=e25b2O)OZ*n@_yhYxD7Qb*&g$|9cJ(r-+t0wLJ_qB@ zN>q?PaA+Uv>;MOngC0~zXd}F@e>^(Azp-94G=j@F07?`I74mm%E~v`oPGTPf!BEdm zk6io=y6QP3NJ3YARwSAei55ko<&kKO8Esq}@(0^RXQOW*U8-xZ%Bd@qDh2ZO`Rlg# z8CzMD+rO)d!WFP8N*0UqH8@hgcO2~Ns!uajch$>y1QKWp0v6pL+(pzM6h438rGrF6 z4}Ho)`FfF4ugYnP&WZPGR8CFI=>q2THb&FXS7}_MI|E+i4|Ijrd?Fe!vTyG(wqA;q zHzeiIKF$V8Lk~3^5jkW9p&b-zL;(?B0KES;XoiWj7I=?{G4UZJ)^~1Q0kvPzYPm>P zYGZan?So2f54oFJnnsny3|kgG!23_7@ox)X8iM@*xd%kwga33S^D$H_*W^m`)bYjl45KHW9tEq)ns&#@m0k*OEd0K zj4fbnIe?lH#$ND*zM~jF`?g20D#h3g#^wVYy{Yjj@^saE(0rUgLuE=PhRTDx2wN?B zj7b4s6W9mfQ+Kj-m>Q*0f1^^9RVpW- zA29WOX&?7Nm71bbIbA)&)NYmfEtQ(4QoRWFG4%&3wN9n_Rca=JPNbsvofs6d6qQt5b=Wnqw z>RVN68-f_74zg_;-LI?E4wc%8Usog5I2f-OgMR}T_u~(se2vQW<0yL!1 z0R)#Rv>E82LJhR;HPpXN>0hn%$FM7-oe<iDFfexc1`!zjeliCu3$P>SLDKCKRKDGBAwz8@Gr2 zjjMVw(ux9hR4hru)!nNChgJp#>ADZnuDTbJ;FGl&25OD1SD*?LzU86kQtH5FU0k(U>)4-f{H!yI2$9Bd3cs!;_x}TI&xu{dK-Uhj3i#Ye>9v0_#CssVnsG z-y{wP>I&Vb;&7X;(48s{XXy%UQE@a%SLh}cM^ki#Zd7qJVOQun74KpEZdE(ojBiu% zUdI1%O!Deu{KvpwKCEZf9Q6Ib{^z8Vwzo;Jt5t$v3xm4-4AlJE|4md9=2xz1)QH@~ zmUbfl{yH_kiUyfcQSqfeX>Ajfwr*J3ZOs{e@aWlav)0Y6n6fmJy6;xHrM<7T<#W4gZ}Eu==J^M-GitUI zEpj&mnGL#hH=DStz6Zfhs{5XZxogF!dQJyO?L)AesR5O`QKg1d>Hvc8G4*DZx=f`G zs#F70&ySh9N~NBwQe!y1VX#23pQ#tB)EJeTtWrG)x|uprrGBuR6HWtJDgWTBK4r*MH2^ zuc*{DDz!$X)*|?vsT)-4VwKvUQkxJsA4KXEDm7W9HmlSY1aV9~OQnAD4JmJ{N^L_h zm8mY3`i@HNP^p~=&SL5x|3_-$fJ*IFsXYkJV``U5ZBePcDzy*6BBp*{rQWGhLn?Iu z!KF-XRH^wYbx@@m=v>R0x>=`Pm71bblU1q*!Szg?r&8loYKlrt zMX-*klU3@`hov^sRH_$2E>r*d7b)-0RjOa5W+EtH>MvDln@Y`6sW}LWnYve{KA=*I zRBAbb3Z{NTrB_e4- zWOkMfL2yDbz#M<)&M<`H9!-MR%?J3)Iy6| z1H^sZ!z!cHfzR!geyu7aHgMJ&K<37wYk=dExdv!aYk-i0rsrXWf@LJ+F7|~I@BDA& z3azZW4IgS-5ub<#s`DL#$gxZ7IW;HVxtnWb8MC`W8^xK_eDV+~1-P{PJ&5ahz3!;T zAHZ5DP>pGLd&sC-W6i-|1iNiD;|tLo%*XYeHD`>H1d|e&k8LT_SJ83A(e(1+jNqD? zF*tqbOAl8Ja!HYX-D>RDb6jk={eD^cG785hM-W5^-SBx{^Jk)oE31}QI=$v zhy=OTetln(>5fc)6&2LwJ4%To(;Iz9>pI8#n-ia1D6^`Vun<`1%euLrrLeNdLXq-T50gV8JQN7i)>}=VinNLz$Yzr(OQQYMhSNE3e$uD&W#2pvgen z#8-E9DAWTq1!$*2yA_%WG!1BvLVFeJ1?mUdr_hi>Gl6CS9Z=|?LUVu?0p)=d42zM5 zSy~RX1}KlMfF=uCSBnDr17B@m&{*$LU=yf=<+z06kFYA?;`P$5fy@|%ANyb!o}}=1 zhU3W!e_=T8@i&g9I4#L=eK174A zohb$6F~r+!%G=J7qA9=h#+VGjD{tG!B5KF16US7g?DEnlSsx^VSIHMfRZyXEM)atx7=IwnA6SQ|KM7>AKX4_w)jD)5 zKb$Em1+)ir3g}eOX`s=S)}br;y`cS|y`cS|GeKv8M)z5V?&Hq^T?9G@bP?!s&^4gZ zW!9m~G}O|L#%AdxfqR4sJgmA*E&GZ;a3_OMw-50^~?0<4!Fxk6#R zU<04K<^c~h9NIS>q?(tn;&8OHAKT6;rk=@mJ;8#38`9TpSQ*?nsCIaDFVtctXvR#? z--bl#D_HG=}l@h0>1YmbgI9u(~DAmz}0TyKpW=7X{CiUD zz-O2GdT)ER|5I2z+$2XQt-9-vQdgr`wRmK!uAx=G#N?%qVvbyhMS)lad*YGP;0X;I zgkgg;?B)KABNzr3p=BSucOuJn-#=n~wWE^zFBi*Xb$w(3Rza3!^{hewC$vs2oM7FH z{Vxdn(3aFbmT^Ms{&C-k)=i^z-^9GqTZB__u`S+2RrB@ z6@NfI(T}R);aYI3uFw@UPA}^gs5rWCSLko=Vgg+IoD}&Hvm4Q0Wog-j z#&be$NcTPm>d_r(CH~mUpy+Dm8Nf2DZhNQl-*{c(*(ie=YX)iDEVx(y6Vf3fDwx@- zW@OZ9O}-bvO1(VmzY*+Rz7T7pe~E}5W$uCJF?Tz95bdK8z7CY36G}Sh_T2h(`C2KX z`t2gC-_rM0zx|#{MZf)%!W>oO*>9^Z?|&NrbhU99dKMkS*DA}x<9b&T*ALCAqqR09 z^*=I1?oeM$fCF2bIp{sx8QUYqj-n1bG%QEn@H_C2eYdp`bM}?PbS4kid8jWb*33o* z&SyK3vjw?SA;y;Tp?94+YvkO63bNJ0p}sU(qS?!XF*en2WuHEKgJS@t9-OA zx=`Z152*#6420u<50~!pb)pIkwGB%DQu_7jYtz?oN0Nde1rs4OR<}TNi{G6O&x9>> z;}(CgIY-D1oE^yv*GE7=3|2F;T;9V)5iA#QFOW0AUqvM1=-Jg5sIfaB#636Av_K52@>R848_yZ zC&*)Rdqa3y-x1`APR-+Y_X5Ddq1+z<3mW?^LH4wnEWw5zL4vIo(#9n%Hm~};22xGk zg6wLxcsgDXWPg)JQ1nh9D0+j1G(RWEo>~iO>ky>9#zH!t5oCY4h19kQqV6oIqCYN3 zFvsF)X%*zLEDLGnO9vT&Co(nSceemQ(fuY6Y~C%%9 z4|S`T3-VaVLRw1%d7@7ves>W76us93g3bAY?CG(Ph8#hH-4@ceUXb=q3u(#{WLJlU zbgU6%f15^7^h_WqdaH#rX9%*V#X{Qrg0weVNXIfk_BUBbtyhrx1`BDpOpsu$g|wsz z@>q?9v@R6niE@qj-KhXj^db`oHqQ}cPmYB&qzDqsvXHi!g0yE^NRvkpbtWSnr(=d7 z`@Nb6MNbBTqNiC%^Ath$q*_Q@k|6CV7Sa(f$bOH7)W!%>pKKuwQGx`METqK{g!xaVwh70AwG`nT)O!KK{+WAo;GfX%?C>aY2xYyBfOlk zsG`3o$bNPB;^Q#a2Lwfz(;4t&1e@OxWRE(wA=1XJ9EQ0LIffz9@s=R_+bpD(vvvmV z?pjF0tAYg8Q4ytDx&?Wx+2U#C+7?A`(um*P2>?ZJFo9q*kEv1gS_^6D5F}V*A#KkH z(q3*MO>KhgDzcD{#|7D+qY)IH3pEry%R-tT6=YAQg|xK@((bpAj@^Rn_gY9T_gg4> znuRnxC`d5XLRy*xc`U_3TJII)36Dnn?gjuTda?-wo9_~2Pm+Z+)Cv-ev5@lH(By_i zX4as+<+g^jcTE-MG~WDBBTi;HiYvE7q@}Y;G6H*e<3y#F7om;ic8a9d=20q>qA)~N7<)CTr=hBm#bH< zX>v`KYl>Vwa!r1$hA$bt#WOVYqMONX)lmu4!^j zm1~MzJ#tN!Ym!`J5Ph(XLcBCKjnK<)a3?!c zx|ryh7CM1wqc7`)-~YX|^WZ$iw+I|6g%0r*)9eo6}Vf$ zXIk(~fnQbdJPV#6aF2r1E%@V~v+!>zc(n!pPT*bz=U8yJ!0#xy!h(M!aG!$fE%;%9 z-&1gt1=k52Qt&q{xJ2Ni3jV$YuN8Pe!OvLm7X?11;DZ+Y1%U?@{F((P0Y3OUkfFN~ zgFk)-j-mee;m=qRT;QWgBL4Wcz}yJ{j`-t2fw^S>9P!6ifw{K;9P!7U0&^1rIO31n z1m zJsRMMKmJN!Zsq_-{PB5#x#{oEaAJYWRP;kT_&k{IO!4ZFq6L^h+BmVf&PiaY(f+PO;j=<{`9P!5&1hyo zBmTHZ;2s4>{P7Hd-%@bIAEO2CRdB=~2fE>pAJQKS!2o}J2OLBF@n>McGagDZ;*ZY? z{GNg%{`gISLkf=gV}rm)6&&%$TLd0ZaKsk76AHOXy55NIO{IOAB zo|FTQ_+yp8JW>Z7@y87U^XwgP#2=Rn%tLy>5r4c;V4mg!j`(A;z&!Q`9Pvkoz`Q>I zIO2~Vyu>=;jRe3Ee|%G5-f;jN@yF)`=6wmk5r2G4V6TEB{&=6j%M={($6E#VD>&kh zIe_7X8Nlg<$E=Bbg-Wm?wBe7Gj>@@eD-q zv~d+S^d1eDYdGM^w0O)DJimpQCwN{9F;DP#exfv+CwQqEu}<((Ou#z9;}HvmaCq4v zg|OeF;i?xWSxFX;d4d;XA?67lk7RVwx!}f;)*uc!6k?v>4OobIf)}z7^8~NYLTZ~u zkNqCagM!%a(QuoQ5wPE*xmOU|J(>mpIKJx8igAzTEoWqj8!%&abDT!Vu=5%r2iVj(&NnRV!%kv6$7!>$UkS!@ zoaZg_Eu=_3SF9%0H$9crk{+i|(evb3B#qosZ z7=Dh^ZE-Yej^XDxzp*%qHOKICod2;nRw$18S~TOZbDZdJnpJVOX5s)g>>Ou?#q{|B zb=bpkZ`e7`Jd3FpOb3^P3|$SK{>VAbDzZS*2(^R7I>*Ve;70`JNQ|1Uu;Bj?m_s(; zyDYd|;N1#-$b!EtaEpRlEqIB*k1BYd1)nc4rxoaa)qEbjUlW)m20XsSEPRK+&nfs+3;veCoeG|1!S@LKf`S)XaHYWA3SMEs>ji#Q z!C$supTPPYr`Uq$3jCJh{)z=p6S!Bw4Hj$&{EmVjw&4EfSSNi7e!_y^5coX>cUbUG z1P&?qumwLV@KFW7Zoxr;^*PQv7Q98^V~YDv7Mv~cpo0Hq!G6H-!q0$nT^Ri>vmq{2 z3H)3(6V9>{rivmDaKM*YaQG)I=}ZN$vEUG3y)MK$aL|m_9Ze#MVF!QS6n>|Gx4aY) z!21%YPEDuU6I1!5+cBD^m}BgTxI5Mr`eh_B$)1S(x@g!S3*%tROj+ZR>Ud3uW{EUaWws&KN%cu76v|zM)crT9K z0^h)JAs;+-CvVvDAveBM3tRG0rzs?axlBUJw~sq z0dwLQnIEV%*h`Fa#>(HI_!p0rze(}0i11_ah(|;N9I*QEs?gvVyYn18GS2Qig9>fk zdDnlA(4E6k!aTO_d~L+G6Lsgh=c7&ME>zQ1X#%<*8Z7%MXeitS@%o&x5Eu`+X1 z`RZ7iXMp*Uu`+wW{Qa>q&jj-`V`b)e^^>tO&jItHu`+XT>mDofLNNbqtjrt z%m5gXqp{%JKWC6*WxEGKXwTDX z+^iGSvEu@~U&aK!b=>Gq+~6?|_(ijRK4il);jrv%`!_?E#f*3D`27j2gbwgaUR+@P z;m4v`y{uFfhcrYx9Y=6l15Uoh)VQk0ACxyJ_wln9`n|%hz@nGx&kW-O7&`R;KdeEO zO-iNuOcB<3cq`;3q$nL^xKJ^m0{99?r`vxy72kTEjU`@Ko;MLkPnR(l-=!|>@n!1%?GED+OMc4mG+dP8V+)49Qu}` zY8CZWq3UZ;afhUel}z|njV9YjcGcG+;BP2z!%*HP z#hZh`ah%?wp}gfJgS)5~mbEazj?l&Cb)uGFNG7wZlT-C@bqf4*+m}7!pXY!{y^)mi zC@PihuRQNfh-c_xHi}^5F186?{nr)J!F&zxm5Gx_3{j8qg!rb_0+xK zfqC-uWH8vNtP~~c?er=(B3^jJE0V#WcaVAPQe2W1v^?H{2D(TUWwf@=xg^ro>Ry4o z)}h)u3+AY{{{7=nbrcPb&eGOZzYIk}72uUB?&^*HCs5gbJeAfcDR`F|x&Pw{u}`|$ z8xUtV0}s01DunEQ@{;{3oW6|!zwshreltPWKzo`LQGMzN>eEkWmMA{D3f`eHtDrqK z!lpm3^y-;n9C@VjgIb4Vf8bOms&PTRAl-}t{VTo4%l{h4dXHBRa2T&ybx+=eZL znrfwEUGZo2wvuXquF&_v7LZ1(+s{S~C)O|g2b$W!#tV!(LY$Wt@tQP9z4+02tBzvm zkT3h0Lq{qSP_+z{J8iYx>46_ek_;8FDv!oC*2@3_a*ZOznL+v#N!PdD?MshfESA&e zYY!nQBMd}Ts^L=WoB#yLcl@Pp^|Ii=!qyb;& zdfs7vjqFotxm|J}Cn$;z+##8Fh00lj^_|t;gPkxpbT`ge(7{3&quyTQF&bClBx-Fa zJxZ$(=#Ce7yS*_e{aSsM&fczb zzGrJ!Rd!x+qSa;}G#Jj%B3bLcJ*?7~oD^#FFu@uIK5k$0z zqNSGT%weMVssLZd?h2i+B(Z?Tmm)>7nUV`F$qyd23MrW?N%M0CO3C}+fiH0d-mH{# zQpulDjjFhhMU>Dh98FNHEKp>ZP!O;SP~5b97uMHD*C5_iPPZkqQSV5o>r2z4r&xIJ0hf;P~Pi?=(m+{L^+Bjl3Hd2B&Juc#4EXGmxPLHHf<0Lb0@zdI z8!nAO)tC23hYa9TE&+VXr7@`b+8*gJ0lx=m3f8LV3mY2z0e>p!G|+I<4b7mvp#7lX zJR7hG!v|dg_@GPUDm3v1tb+YHpo>7GAvSb_E(cu$8dZePI0YJNW%yDbbZK1M=MOYB z5it$7RwlSt&t`pyrRwq}g9l7LScmVgDa@m>6k??cOVJpt#`oJ4ma4HdV#^hlrZJSJ zD>PqWUXA&QouM$l#!$+xP@KXtHI_x}<8O(5SsFv>yF%|OEJtHS#D1=@B8{O|aQ{nT zsQ47E-4)=#*-eLXtmJq|_&5Zcr&C`9n%G1Ei#@6q5WQrG)`f zzMxV_@)x;5=)tYAP@tOMtqC<67yI6;xI`^de$A;;EmF?A$^%_kq|C$e=Ri5!6Dm8X zCsc;2Q{C{C7P=|d0NxmWX+u7*fDczp2{<*JWQUV2IN1)*uwaiJ_E>O=9iC~yseqAV z;0=H9vLwH}hI44&OR!Wv394*$ebcnip9Xe*k;gT=2XkuhG6zKPY=;(!M#+>&&m)$I zS4140_)3o{f#*K71eQfw;*p31stlP>LJ#dWQ9K-?MRAg%Me{6CZze=hgZP?55B4j* zESzzm1*CGbR1(HGRBnz{0XcR!--3(ma8bZ%eoSYP)>e-6VEiv&1HK{gnd22yp!zNb zD6H|5@RrcBU2|UiWTL?}Sl#x|qPM)LMEx}o)n7F-Yee7R)+KXWB@65^t5JptE$EI^ ze!aQ@t_86Z)>V>e3D&YB*a}lGx5l+=$rq#SiE@M7sqX+|$v>)>9~)4lGlu3YDr}rK;CdX{6D5-1}eCzYKvUgm3Gi;9N2e0WzEEgq)|eRzp#nxB3Rh1L(Y zsK#BX^PXmv^>563Bjoz|h6c<|3LJuGB(v((@y9G>Iv&Y&$7%7YmU!Y1Abt+TcS1ZA zkhYs}Ck+U$eTz!;A<7PaW) zy;?5Wl3PN#$0#?MxsR9J-OJKd@n3yNiZ358RmHzjYnX0nxPcn-sNr>Bb=#kbsk)xm z9l5whRi*K|V=b!#e*$~gvc&uY++n{tTin{pw22vv796LKAa>SwHTCiPV} zK6ioa=r0`{PwvfI}2R>-cZ1En;VLTejWJp%(n{;&K0 z_II8Ez^?g9+1otNlf9YyT&1jUFYjI+NdBSCuA8CkNMd8PrR5(1e4ns!l`6I>v78vb z@t_p?BBgw*QjSJ*zkG!hx_d8fX&DDv?8*}&mRhGpI4n|o0o&&(1FLFr_E&?_;|Y7& z`RU_X6s?(U@z<|PS>R9lD|c2~T&m2{ZSn5s!p91nugvP*dp*qx+0D8Yov8m;fYDa? z@}aNgKne-uvmM&Fk4-$7@;I9Ii)3sQ#{IMo?p%wyX@Fc4<-*lT>gM9gz~5H}1`b>U zA*;oIM4RE_0pGE@?Z?KM&2oh@u@5HR|3#^}zP&{>vD_~F7QExg#gGeE>*kDBav{il zNy&xwmQt?OF1MRU#EWrMe*vxC-jb4tK{< z!@*kGpDbRg-aHAYPlDA6XjDzXt-K^8v-8#Mk6}zE;KwdUNinbBo`4=6`(SnG0IIwH zSLj>*#(L3e&I0luis*>|X;eh2(JP-3#eUBQrSMCls7@P{dV+hp5nbdOa%;lq*quX%!NYn3*cl-}KGO-g?ggY5sclb<#u(T4Mt z4OnG$g}$ls5qqA7IJ9CEiBOkL-n5#MRcWDx>7}n{9i@;C}-VwzK2H3k(_pznpAZV z#II6Tv)6>so6}_r%|c!YeoWSUbmDiHc%bLdzB6eDGd)<#dKsi8Jm3TOz4t4l8Lvg$ zoOE8O#iWCwth!0Q$BO|E68JM@C{fFT@o$M`m@Kz9=Rjb>b+CG`tAP)hfq+OxQS)2g3?xS)1 zL~-=_gRAIkeY&z`%E-P?Dg*u?56|Gi7V*Q*QM3io0;(pihf>t}Rl+DwG(V5%fY_CU zhPeJ>4;l)k9sd3pS%V=8mL{ z)v+QC)#0^Q$1WPhO%TfT_j@HSrTSrkN&uS6Fu=_d<^)`0ZcR2?Yd4B1p_{N zF`lSmhYajmFN7TBV$NpgwH8iwa{os;VcgtFI-J2U^o! zf^Nmo8evEt%J4nK&=z5U!FCOID~66EtjROAp$n~=G@gQ?X*9G+4HC8VUJR>T?Wm|8 zCvsH!04uQn5)zI2(FMbgZ~I~sYB{(XFG7(KMGfryQZ8JgD-^m%irohX9i1t!QJCBed*^8+BwfJu>-^G7L2K$mw zOMhR8-js%lu?CkFwjT6fw2Rw(6y%!$RNQQFA_d$BV00rO5mZI*1rz!v?#%@;5d`^x zc31Mg zv%rIfUpsi9++IIlK%E@94pJEDyF!76NDXaQ@jl|;VnOPB1NeW@EYG;(@Ok>0jNq(gb3MjdfA9i^t21W*ksHiV z*?&OMq0e1aXU_Yt#4~H@su_V#G6Ekj3;a1fJmnpK-C>9S;@?z%fMt2i4I9j_ZrT6O zQu+TCKFcF;_ERlbxdZxns+Eb8by`NkQqRsv@JZ;Fjuw(!7G~ z((26{3o4AFg53OqitLSBs|qR&VA**^#pRVoenC}sja;`H<;67xCE57}DLc4a|HL0*+nRlK>NvMP6TxlvG4URGIMQIJh2yVA%jt1hiVR(WM5Wz`kg zo6GVGj7_=4r7BicR8de_R92F2no>|xRZv=4TvnQ0oDW?f@(c1s*GTG1D~*lCRoc2) zmB%%X@)*x0o>`UJZH)ZfywTl_iQ;k*UpsMoQy{_{@sAU<^DvR&`iC~^FlNjDO#PKr z6?BEFt>p!t%HnNyFCHRFqOh!Db1s_7tn$=IbY3JnKN4LKi7t#p7e%6rBhibDa`afV zfAP%~)timVqTF&cdVXd8NuxCXl%|cDJjeI6y_F}c+f%~jytMb(iqffz9!>z z7m;QzEvxb@NL%QEz(tGG=-W0u1^J?hbyrYfX(_D8-CPhi0w0Sql#BJWwzRUkyu7TU z3fg20@W>c22X0on31c<-o#)o#k`m8GINj#*l7h_z=;!&K5)9iFBid7ud#m)7p?R78 za@Gwu&erc zKg?+8SmtX9U6R!JeG)kF$5lt#^_9?qr;;FM}3twG+Ciu6Ly%>~yZFLUJg%o_=uKN7fLByizK z;G&Vh#Up_iMZjh0OJSiA>tRGqP)KA2#-gqD+JHqsnQaK|ABxcUp$IJ>iqPz#2yGsU z(BPp6trbK~a3&@5oJpwZ&ZIc8+2fe}Oj0q*9B4u^(a2P2M>r$eX_+kj7Q*?_BqGz~ za74MD7>`NQOvT)3M%5H*QkY52C?-@hs(7-~htW$E&32o2iNRpL3Km?VCn}G%mQ!7G zp*Xi%(JAM){66h?zb`fWqv~IrZe#*d*OA>nr3D_O%T|qi`2~3;xpMHZ1wrn{l7h;i zOt6c5Yq+?D8Puyg0Qbi@xvI)VQBvm@T59#tjs1LUbHV0H^JH!_mbY=ns)CA=;?iZ1 z9;&~%6srT4(XP}o00$AClCrXLd!mxBDyzyxJ<-Z)UA;qWs=aG&I(Id)3y*BfD>-2g zov$PN6!O})IVrQMXLFCi8GY5tB~shi0kd&*lc^o>X!rsC349$O4k z2o;>{Mbp!9;))6=*8B`Q!@sA zB^UU<0^YKhowtXkG)7l*V zlYFfm*FWJKVKO^m{^mKZbTwUJC-T>!^@T&;e`1fdIRM|#e#Bl=j3eY4v&YEo0N!Z8 z0JaGOLltg4NZ-QrS-cs3961%Bth##;2d%V$KXs&MAEye3-U8roivBnP-_WDo(fObN zr{6p#(|1A0I>&=EHr)TvgL84A8cA|XIN)r>UaPng$8T{XN4I zC59Uz$HORbN%of9l4?}taLe)w3VFzAOR$~FmY1OFXrd)$C2p44!z{ZlhB~z>-k4oo zRb0Y>eW?FL#&vTX=6rhm=sVo+FwQd>Zw9@8h<;($7Gg>PbtDFKHZK4OO z6@(=EIhH`SnF+g zo4F=OcV?KjaWTcQ71&9N~k9!r@mD-u_ZJJb-X~ zcQ~Ac$DRK2N;u5_b?lcv3y0SrJofW&xC-Ik*TUfk5yrj|4nKo19pPIDpT~1M#}ID& zML0agZ5Yq?qMQhC{x8TQJoY=tBh2p$ho3{puPO28*mj-as7Z3179SnMPh%$mn}NUX z;&AvvGAxTuB9@B3_kclEelu}hhQG|ha5xio8wp9v6Oyk?9Di#}t#QTlOV3*{^K3Fw zR|)=ZyeS-B$5##06O!(BE}byWwKf`AO8UKkn{Nq+`8lpg`kPkzI8JdG1|RUA37+58hr@^BZ9JLxyY7n$y6+uV7wvjHUf4ZI&IE529%Ksgtzl8BZJ`-i;?|Rxw{|xCj_Fz0i7?Hn78lCyiK>cpRc+x(^ zzBbFg%aESu|ULabtNx()~_fLh^ksUxFtXV8 zy?dNLA+0WYMS{09AuT;2H9a9^NrGodLh_P?q$LS4G7dcoJuT2f*E{(;Spz3);A9P) ztbvm?aIywY*1-R*8mK+ZD_LjikV`QBhKEmb?Svn<1N@~<^Ge9i6Yv+)e4GZxcfpjsAK5dA(ujE#MziBEkGADT@X5t-5iZ;v9 ztSc~9^PBnOwP7hwjph$)+N|#ZO~0F{^l9<`bHRa}5%Vh4?Y%{ZckA#W9e!7b&+70c z9lou@_jUNO4#y>XC7-D}JXeQ{b+}xI*XyuQhg)=bw+>n)oW*a(&jFjo9daLI)7g3qInBFDc9i; z%%5AO@C)WIm~GgY=gptHa4rr<*l&1F!hv8#`b@`y@_F;-EijDNbbe;YS3%{c_}mrM z>W=58yu4u<8^&;6p0jVnaok9}rw`LxUQ&%SZ4YmqUqXQkv@qGsKCWy%Z^boVGR||O zBb#G`#-(c~4$*r)?r!DXoQ>P#l|_azc}UuMd4<{K6=i(76i4VBpvsx-!b!%2G z|FR)(_44Z(@{@Wve?`X1B}=oiveQ?u_JQk~t5+j&m_5-Pd(81n={!q@k72sXHshTM zbt0|LK9AQmZW1tj$5Z{phO<=Ja4uhhlXNDG)}}4GP0et4JDqG(_JNaada|FQ6REy+ zvY%q$Hpdi(dQ3by_MRMj|Ly0~o|9`Nb3FK$TO)Ce$8|41X}Kc(ydn0R?fMJdzFen8 zct>6z43{~%20OW~R&(XdlY1rUV0iMoPqyip_Zt5)w%Hhf#&>dh9mKq z>&UB4u%0y6k*DZ&;vB4XWB}7oQQWPc`asYD>o?qBlOcb=ED}lgcSdk7nuC*1&Uvu?;gfWQt>-3G5KpZEB=p8Sf4*$Zt_=dSN!wM zhgqo9_EY+|tupx^yTdD~x3JTU@KgM^;1;r~&#CoZ;gSz9jljPJ_24!f!aVIsFr3b( zQSN~DkvwBuDtyQJ_B0gNh>D3`!XPSo1%l+5C`Zgjh($T06TlSZ7{^yWqMYt;A~-e5 zjTdo@aht*EI{(zIBJTbK!MHg{cFj4B8fCxgdPtJT%|nH_zIGZ}qrXpn$GDrpn#lO{ zkC8)f)VvtJmE!Wj;HU-Bg-9@5EJ)Pi*hdk>xYC$%kq}9)Wl$KECPcD}kI_e6EQH6! z4iR;U5Gk(TkhoNcR97msT_!}DD}&lD7sBhhh-_XV{I2g&Te=XLuIorF5hBawXB{k? zx)$6yu2ZOO`IL1aid?DG<`=8WU0bMar4UuFdzo_O_=!5UdH?aZ0vP{0hXH}{f8YfU&EP}WJARXjyBIH$cyt^1 zllUegMR z@k^rwel!C2BG0(xj(8U65aB%#bEYFU(Qva~CS2-BpoWi487Hk0r6XMocPZ<1qtcj+ zxbsn{cCx`m5^ASmM?Ai2oT$B+9MtbjC&wzp3^)Ie?eWWF#n!bJ163IA@4%+<3!_B1 z#7r~XDTv1BIYgu`0+&Nm{N!X+Y7=&{usW-JL=#?Baz8N{j7j$+m&9En_PT|-4^i7J zr{o>7;4>aTH0Eig!(EONB&Mo5n~H))GE+HDx)t0Bw~G!h)1~ku)Twdi)iA^`L#=oWo)@Xq##l~5VM3q{EhY$Y_ z$%p&S_DZt69)_4>_hopBFm4*t&P@m4+WB~O+z(;HH$2S6wX>xzDq49??%)+&^X}hBsl8?t^C~~VK9tC`_6#h@NUj zL^X+Oe;MXpsmazI4vzS%G}*Gl5rfoBO~N^*p}tpZ63!8Zs_Qk`u*1;-*)MCGnr?S& z2lG0eTDxQF`T=-`a*qvm_qfq?k4Ml1+3w9!8+~69_t>J{WAOI)b!T}|TlncFhdu=<4#~&0bKrI`iGwgJY5yyXvtEO75}yPkCt#q&%Ike( zmHZ^QPhSVqxbhml#@>j|GES|o#;MiSIJM{+r#nG~;B3w> z%vc0Sufd|8BG>Gxmys(*)?iUwgE{A%wiFOr0`Z4Vtz(>PFz44!V|;qd6x!(8hYRxK zQtULwqcWh*l{}dXl&HIro9omm`HcUF`1C29QlmIUyH1;O58@NcqoTN2alD1XM!91c zHyjs1Flt;9ZHjU%ArUP^jAIJfVuXlytYS*65J`?K5^+LIapaL0FGRAVltjD`GaOq< zOc283c#TAY5HlToWi~2Nh!jVdDM>=iaXd|8q7bQ$Zx%zGEI$o+&Ivj!Q^*geWm$*g}=4;pnA^xQwXBsqHM+ z$DmG0cARrB+QsoAF!xN|5Jyl7_bd^Qa?FG-_qjsEI5_3FzaT`sDWheQiWLKh-1n;A+j95BQZbrFl5#{I7Pb`#IdBeIsQls7RK;@yEy7NM7BjSAAtBv z>^G3ISmcu&vE`7tNQfyIs9908Oe$)eqG_DaPDRr`p{Jwc$a*j4O+fq;INBJeR(GO} zSqdDbq(3p~GmNPDG%?M!1NNR${fw2EV--R@$54N_#V0Wp9QI(WaYWl@Piat`5;#Eg1TWgIp)@9CEw$@r{taPWe*7cH2j#FCeOG4y3;lZrGEY~==WE6L# zIk+v1P7@;8!EIsm z#X?}xXUDljh!h96h0&J^k?P>KF#0kf(j43tMqe(3*THRJv{wkfgWJOBbRjYw+!jVJ z5hBaMZDI7Xss95za~!8o+wv)Y15xDQwlLZ+R+l@tEsS0%M3sZv!ssiuAqc?~-tqyJrqi>Am(BJ0ZwlF$7ZaLbo!@+G~bdK28>EO07 zdSlEiD0sn$;j;omlKagoV5*>JIGrw}-U+rs$91jZ*e$41MFa25ufST$Q14vuB9u@jjPBV$=?oDfMe zmc@=2B3Z_=*mxm4GM2?o5F$m!ve*P^vQ!z%ViSc(ld&u|NeHiuWw8^5@XJ^hJ866- zGR>5+EOxSJ%aXAyc8U-=GM2@jB1DmlWwBG^)`QC~is&{UX(Htpn!b=<6a7l|s%_ zT!lcf!uTs~`wQY{CQQLK{y&`)>i}^tSv)64 zNhAJKT*tewVv=02Y=rtlypSP&DRueEhl+CSH6|ZGW)sd&povXPXT*7w`svX|{Oh)H2w_n@`3HoH;yD&M zu;CKZjRZP){JqXZ@_d0X&l5yKT`pnmBy^DL$4(LUlZ%z+WEDDPY@1pGIGsL z@=Xtfj@^UU=OsP})$68F!nLzuM)KhnV_M-xW8Ed>bL||w-CY3QZ0XR> zoon2`flRKZGTrQzg__E6bJWe%8xC>xhTm0veN866^ zne)BK+%S0b!rxRR#1$Lcl2{by&Jtt%`xpRHe6*`dzb&`0Ku`fXxn3Z&uPW+-y zbeG_y_a_N#L)XsM9qv*T__-ui;FcZkdlL*}f6@m~vMKpne3iPtTcm@F-~rF)yST;jRXa$7pLvE>pkm6qGmu`LeYY%(UrP|Uf->vp1b zCQan}$F=1rXaQt0O*Ph*BKIqxPL%=0xh2Q_5~%5k(#N)BjeqcbFY-5x*>W|Er=buP zGeuR*7BtT57kDL&%O(DL!QuWTl+1}|KXGm8*=8g)&h<)S44jQWw*ysjX*|29Fc@c1 zTtqKapMX^dRbo+o0jM4!#TLpH%LQiro#xvVU;8V;EQa2j{q?gCNxY z!5J-t+CMmBgi!kjXRHuv|KN-hLhT=%r_De z6F3^0<)~D+xyTbZN=bW7`V3=Ak<;ak-2#7+CA2GDy98%{*Agj+T0*;)3Za(Ju4O`~ zCA7;YgjzzomjAEzz6DIK;yUwo->&Z4@1FNV4`w8R5TF^2UPvIp2tCk9LJ~;e5fW~V z=AjvDG&9Wf2#H_`Bpf?&Y$NR0tSt)+@!GKwCc7jH$PWz0!LgID-Zj{FOrHDOP?(B#*;ut$&KCTV7W*rUhr1_9tg z$LK=4y)GFU6Yjpy#5r#8!up^gtPdJ6)x5?D>*It*eT@^=#|EH)rTgBN|A+!H9u=tf z&0<<{ew)M>k9K))M6=?HN0-I8qtd>3bY=X@06g)%sAJi0~z?Tbg(3ZQ-QXtw~`7muzJK>Om+YXs1~cyvSKZRn@=#iN_*?*O2E z@#tphwf4oMJpyQ7Jh~kM8j90yXW6N3YMG2B3ZM z=$7gz6PioUpd04XW> zq%BzIC{AsLh!*rgtO(xkW35^-i91J*kmN=@KN61Unc z(@2(n_Q0JRy3rxWk$0Bi89H+Y<u%UlQ}p#KQU*_31wwM+|!>tG51I7yHU|`u8>dk55;nKq947w{zp$Z7pycrvSlRy z7M=enJO{;IIW+Dxm-nJwZ7v@J8Jf%ToAb}(eDUARC1$0fx%7(W(yL-Fy`s7F{uRw- zeRIg2AO9v+nKobxf(GnDQP{?ST_k`pU<(B>2JB)1i~(CDfH7c~1P$1w9-A=+>@x2M z0E_`!?D4|V7_g2+7V=~aSf@}k25gA{#(;GRU<}yOcq8f<1GdZX8JFs^G7k!6|fZ{(vm--HDP|(JA z;O(WrbDbCu;@nj(&HAru1%Df4trcXt)C#V^a;Y3KH9?@z7-q;;9J3I z0KOIM1vTFa4g>J5;0IC6w}P}wz7?b$_N^eh<6FT&)bXw09ss@-WZ!%%NYh)if{!4} zTEVzj!5-u*qDAo7D-jJK*C8DjD|nbGv4ZpwO3fv#Ag4A%`)REp)5Z!Wcn)+t%q~3x zY?L3y3No3{R*>1>w%N&|75oWt%ybgk3Nl>-jTWV0jy{Kvq;CaDZz1!fjS?%!YMX7A z*7okfIj+llLF|YUpFOy zKKgaj0_dY(HxnO5d-~|t%?hB8e%+h^`smlK5kMdPy0uAKCw=tm)(JIz^y}6OppSmt z1_AWZuiKcYM;(3i>oy5Bee~-#3!smF-4>~%kAB@&0qoK5KY~-P3o{wz(XTrzfuvd$ zNxuzr<>WV#$uRB6$!{c^cn1J|@*Bwspih1yH3I09-$<CJfiRzi9$EP#_8uV-*O~ zz5?O#qOU**_zHx8uRsX+3WR{KKnVB>gn+L=2>1$wfUiIZ_zHx8uRsX+3WR{KKnVB> zgn+L=2>1$wfUiIZ_zHx8uRsXwRH8tb+^s}`FzFv%5!k0hfiSsWi2`BLKe{5|D-Z&s zPL>>R0Ecs&QFHZ;11bhZmTHjLeUVrvghMn4LJe47Umiu`HO$Z&B$5z7Ymi7%0IfkH zDFL(wiKGS48YGg5zZJx^28m<^&>AF?6F_T_NR0qmgG6eR%h9OTAdxzurZq^UUI48@ zA`Jp)4H9WgtVSKJK_X2;O>2-yvjAFyL|UYd)*z8q0iZ!RU{`M3_`++sJc`V6888{k zsl;KjhIeQxnPJ+IyC0Q`zXfT}ao>#xMuYscy9N0*yaI{h3WWK;3xr%!ItktYE&E5n zH}CI8j^pe_IsS#t5L<_r-8-RW%^@saUL1G|B$r*tD_+KJMgIZSSLN2BJOb&WS!7-j zXT9+0oyigBDp|3oH#_bma4zTFB`U!%?-a|~rT^zh^DlJfR*?3tVE%k2{YFz)lr&o7 zH_FJNx_@2Zw%fJdcUtY0?@q?s-I+< zXM##!tD8H#s8;2Q!L`xvr5OMh)xotbl$9uhYk|vAn<6lYH$3V;p==DnwMa)EHVJs(KUUnP_jh*7r=bw_NLcCfZxB^*s~qE!X;c4OOoMYdK2XZul2p)wZ6B* zb1_AF6Xji>tplJpQQn^PZ-ao|M0tCg<{(FJqP%@A3jyd&ly{4CM{lCMH^w<7dK2a4 z6J)*KM0xwAZ+a8u9q=e-pK}zC663KJ&WuERdnVdD!l>s6(K2)FmCPKF-$#x_dq?|ob zYN}4CX`7m=7eL$8RD%H8rluMb9D%l}sV1SOZEC7n0BuuKEmB9@)Kseg_aLwl`dHBy zPt9^uNM~22(|3^}ym3uuGE6(-jHk1S-vpqY@pMiA?TlkD!W`|4r)ve!&Um^megT-M zo$++N_aKNZaUwh#5V2SE!_y7!93a$dFaViY9pi@5-$gq6l@yid6UdWTf5-cGTu0Z0 zvws8h^F(toIUc`)mB?!J_boasUp(>{$)7_cKdZQyepBUD(*Isa8fYb&%h-w0)lWC` zrZ>zFC-QcXtK*)aW?7iwo?(u_i7^l)wP+U+9E%fcNn*9<7|$7gGbrf~Arae%-qqH> z+t1p7KI=dcDX9ycMt^E+8P2JzN})hLLnrETf5v?FG)yb0yBOo$d|l?d6|%ggXgd3r zu#8e+Xkqfx43%1^KF!T&pfi5oofsp&>yzEg_py?4VqZjO8*;q92xL*EY5JTLok2|< zzQT^z@%U|qMtqxrCEoA%=V}(nIUyt=^g21wm}toO>VS<$~WqW@wgTxpL1gbmkbm zz=ltul??OU(`P0cE=S!~Uew`8Y{FfQytzpdg6rz8L*C-7bnx_M_qvGVbQq}HU4y(X zj|5Ti_T<2L!C4`ihpuW8KMm`w7Nbr7*kzzkcbr1ZC=~Y{Xl0wU!mnz$Z$@+1XSwR! z)6XAs9pv7S;}YSao%>f9&@S(g^!J_^|;Ge;F}Hjo#QT}f%h6xFCBLoQUOk3bQo$_%Zhh6e}#y;G@Ufk77heP2G0>q~ZOa1D@NK8_=OSvTeav7-ZX0{#Djp&CrNA!}tJd+cONN{WFYD1Mtr< z2>53h1pG4$0{$5W0sjnxfPaQTz(2zv;Gba-@Xs&^_-7ad{4)#!{uu@V{|tkGe}+N8 zKf@s4pJ5R2&oBu1XBY(hGYkSdGvZh=xjQ3{6_frM27!GUajcl!pApB3N&gIkfPaQT zVAP5J2RuHGe=&Zzj?&>bh^OM$FXl2=>BH=JAp8dRiSz#wQfhA#^%O}s%!N4;_HPpj z__v7!{M$qV{%s-w|2C1-OgPM?9-HxR6aN-~f1Ai%kAIt(L2v!rL{jr_6AAdYi3I%H z#0J#aCk~RkEb%OIbYMSj6S*7lZxgBTewdKkL>XHyl+c0wy3?A4?3u7Is$q6c;IM|- zKY?4pVu?kHUI-Nb2|5NgODvL12%8jiMAzPC;ki!S+$a8L^cQhS-M<6fVWW})({N32 z8rBQoM6Z2C6Tlrl|;ag zN(xNFPBRS~VQCPR#5wtXLPsSry)Tr|QAq^86iVo*Bu>_va6(5Vk#p<9GFvxE2lj_$ zw%#BBqLSh!DybI*<0dMJqJM#>^l=Gd8#9oxC>@p5W)4VnR1!2Na^Bm*Z=A(V zR1(uJmrIUc2yM5aNylK>?4>NfrwJ{H4}>PMlz%Bpz`v9w;9trTXp{2OIZTla-M+DBm(}WECK&gmVkdLdoTLwU&_*R@GoWAYyVP~fPX3bJOKYv_8b8J zQkK7*=wHe*=*7R3eHeg$Da)?`_?NPOgdG1;_9+1Vr7XMSU&``F%lu2(`vCZtvh16G zDf=wyd=6HM%P`jRcgUJ&LX&FNVp`pIAm1fg)*E{z>kY`aAYC(niFE&fDLJ$}kCYVr ziYPB}U8z@N=KRCxj#ry}6^-g$saGe|^sdya7eMby zy#@jFuGDKx{1|oguGDK1YI;}dH4C73rCy8F(YsQwRREmya%sC%11@!2ocmL6mis+C zl#bd;^LycOd@r2y)rr**rXYqnm0^Mnj(A!*rW?6`ODqfXY&guBcNQE%GJ)`|Hxfk> zP9vTAc-mz!mQZlg+!Q3RDPWbi5>4t(lLYqjQd)|InQ~kz&@=$?Jg7j!{u}2>~Hls&d zi#@uCd-%}Lqpe4DDful*^gVRu4$z9c7aaKcLiU=G1+}M9cp^n`$*sD){Jy1>|0K)5 zgz^)MMQ%?&cHCq2$qdW8r=L3R)NTR1HpA@Rab2G?&cD!^k039?ZPD6=6c}zIgxpmf zn%w7(MZSn4R~zuDW0B7R>|RL8!w&11^mW~0G7dYeW8R05tBp0jr{Mh&pbZ||;EpQ$ zS<`%@Y5q5nF>A!xr1?CY`X460TRMkj$7$YDr>7Y^#nj(V=&Z|w1rF3$InWyJaZsI2 zg9vA^b^t(H#%>+;;@BU8Q!isrFEV4lL&lz2V#a=lj6G|>r|yW{0&2NMTsj#09WwTs zPBZp9WbAdKFYVatJ+^_d-;w?9Vcm5*_LIoK*c8u=39-ll!PYv*EL%MjAqx41?6 zpj`{|UK;rVqIoTieE)F2yvRZO6$iXSsB2=q%u8wN=~m#SG)cM@(PaRlyoyS5M%bH- z)^pKIkxtUBh`xa-x)sqrd`Q9HKtc-EIZ@7D13il5+cU)5_tEejER8YVrJ1+V#5&Mo z>04=HGv7+n#EUb&mFB~EroJcy<>D;Hi!;2H=HCI;ycO$7MTS5;kCVPy z%I(5u+PxPgGwvp&vrdc+CvJ6LWhd`s`s1OOnQmqJoKAm>=}+kNB~1T;PG7-vpUd)5 zUiz6g3KaFOc_~WGh^>(4~X}dP4fQ2&(kgc0C|}MdMMCwW)#dT z4#kPv7u>K%O)SNP(`sLE!(PQdiXM1p!_o>jY+)hde>hnlHeY??iEh+{3rYg`3!S-= z%Jn8xzIy&2qq{t5R3Arfw*enLq4t42>*oC)ip%%izJbEmv~lq6>EAn{czU*e9(%;2 zMa6Tu4W{lrCuZ>=F0^re2TH^KE1tYeP2RAR)SbwpmDwphzES)VH>QPl?0Wc!wU2<>oS&fUj2HOuUEKij%>|_S_eeV?GhoN; zIgmd4$&g~*>+X>2OLoYx@tB?Ww(y?c;|>`{i|ObG@R5L9#{D%BXi9ic*xE5qq6XQkFojVFIB{MT;iia~D_EELPAhM5V*ey9 z-bk!;l{B1LyrBxMkG}C#H$fag$OFsv0SsGQ;`Q@MgkOh_@TOzKe0H2y8xh`gY`l~O z`F-dJZ#p&^@YUlH-gI1R!0#N7@TOz40be>E;kjIokb+`!qgc~hy$=f|+^Bp63wv8i zhIM*4SA)!{Kfb$LdNvzh6zUV<#2cq#Pnd46(7kppCk1X5cGbuj5#bcuXKF4rW%k-K zL#E75C-$DQGAC@AQB$VZsrj}kv&7JmcBV~!H)eSqGDMF45Vb|%7CLiY!canK(K-L^ zE|kLGT|SS`L#63$hvD%@Peguz3hApiqa5vndmdmmN7C3y2xD@FG5g&Yke8dQ+0-j+ zS{XGAi7h_ajXI8FIdeUlk{&ntJ&qkc+07!3-A7E@G7C%@aPQfZ-7Ml*?(rpULg$h? z&EcI+%{Fj^2565Q?Q)!z$}lLKf&Vk!LWD*u|P$ulpFFcveHhIO>8$ zqS~KRgSGewD$Th9@<6p;{;JNm&c`JD(qUrFM#mop$?!irOsvI=d=M2)XjlW&zn0Lj zRvQ{dzq{dY*+gk**zW@sk=O)!m>&-@3M@?r^PEo7zx;$w(!KlxNlKtk;|3Hh2_qx< z$p7NU2(o5HK8s|ELpcFZ?z>#`j+l6t7X`<~oW+B|Wbu{p`%pm}wD{!$Xp0tKC4e?* z@znxon-;%90BzLbR|=r5T6~QF+N{Ob3ZU&;yjuWm*y8I1(3UNJjR4xT#WyrwfPQM* z7T;7)9jT35JQz$C4+fLPgTZ9+U@%!c7)%!5;Vl9+ZQ|nBXBj}MZCpGUOcvkUv>rLy z%EkA!@aq@a%*Ah!?r1v~e`B1Js102_pCIe?;cq+`Ocp=jF%jFgz=U++PcVQq@>^hTM)ryoZ3brX z2f>cuz{N>jllc9!C=-tTPo&-0-AG4b1=fm90uzn3;4>Cm z1&rq?l1ojvZzla+pr4sYN47wt$n|JidE>x2@^-UyFzzfJj5|vQfaq?krm?02o37brMRT2A-(5H%TUo?@wD%Bgu5v|8$SrF~vg zm{D%!Kz^vH@GFIy3Y&4f_n^zEkLzf(Tm8J7*#&+$-q$&%hjky{W(zp;cwP|23vtQN zT1L~|6MK6%(l7(a;a}*?*TAVbU6*_2A7z(MfAx6$T97-vfHQ;B-{Wz5$@ebeT6Ir< z>3E#+G4D2opE_PQbijGfB2t0lbUe)6`1|AJ6=I*le*{ABuhY=xFb@viKbH`Ftneeq z{6PFKrRF^+k|PKeIwMwv*D5?lcslvFlKHk1;UScLCQ0j$7Z8P)fLEV0nRlKD{}7qa z8t}E_;W#RN-hi(j$2(&j=Z_8eo#XYncXWda;(ss-{v}78FJwQ91dasi=a|gBHuFu+ zpVa8g{U{Ro2E-^u*=5I!yOCnAer93bcp$y&hPQPCjqou;35N>ULkXjIEzpd9+X-Rx z?h7@e?>rG_AkvK{_ch_{O_ylSVjSe`9>dvQ;p`s6*`31KJ;GVC=L_J+%@U{(KD}Q! zIcUZYu9K5PhLf9xlLt-aqneY$2K?v=;pB(`A2=bLe3Jq1J5m1~GemAs`3FuOwwweT z7})7qhnH~y{0p6F!7zjk-i3w@$K#KHW8Ml4-YMhuw(4=e_U158iE?J#`@=V&`!zln z_|7VAzi{^!<~ysj0i*0O60On1W^EJhwVHav!o8&i>JC4R0W3?hWBf*|aA>7)NW}Ch zw0OD6#WYaZx()ce7PfT;eDrwuJILK&NgbDY*(mKWg3p;xQ4z60i=pMXsJ)^+bY*gN zvZpTG3<*?DPaQguW=2xuS7G##1x_+~RnpBs@ppu-ZjoHII=Qf=r*2J42vwqufhurb zvN$L3NXrX_dg@pr-VWNGAeK<&%_gNI$t%_B_L`o$t6SEzK**D!noun`m`0{o(#s6) z-ZLzdy-2#7yIdYM7=TmjcMpRqcCXI1+5W+>9c;ZNjDhIkH<-%8lJ@Ar7WSaK`3@Oj zV_hiOp3@y^cR8Y_n$U%rI&fuHh6Qs?I7i30F~kuhlMw7?o3I&nw4IEnz?V;^on(KCBE=rDhLS!7#Ufgq z{+OM`;=Bs|c4edmEhj8veYr~N$>i`;e%F($$zm-&X%N9AM?j=K*HcHC%lHLL1TAZ4 z(kGs?l2U^i(u{78v#DAuCv`rl5}~Nqa?^ln>IxZvuGeUaR}=#rhL?$B^Gq=a&cBw3 zSz1(QmrH}4ZFCHCJyRMkxCm3&=J#J%p;=aaev7l^+Qk>K)294ckLtA^E1i5#&!$_P z&A6VLaA0Z@ma$38DUWM6Ra|c=uEq3>smf@MXKgjAp7M2;D~cbr0o78?Ob#PRH@K+k zG<)l1Dn)To02(y!8;h&4sht1K#o=Sw&g6eb zF&kE`XnkQL(pJps$&&^K!t^ikwd{yNPK%!^s`#j#r=piNLpb84B9SQSWzbs%wVbpq2y-ZUMOV7A zcw}ZSz--YvS?}6f4(nlS2eEv8)s@MFw#eFUh*Q?UdAA;xxct6IH2K|YhotzvVY5M_ zL5&Vhfi~GX%XkZ|c8Q~OgXZxpi-K?))NEM_;Mbg)0ykF+@&$V7w-v z17W~2S;od|XMTY{Bw3KY`*5L;_hpUBr^=18eyWWDEH7g6g zwBgdwY|P3XKht?I&EJE?{qB^g6Z-e1`^Kadj+EwH+6r>UDjaK0D*Dv9nNxuKOKzlU zi@b+qmGZtm$oqzwyltD#aYcl&k%>#Gu8f->Mn^3?=M<>L$_oX zoYmSr9Wd-UyIhMtObLTaRDAjVOnWw3`)lo5Z)K)IOID*6!Ai#?MbW_(7Z-SI>H5Sr z8IxEpRljhPTxnIe*;U<6L7!J?Y0o!0mG77hJMV$`heH1g)-Z%WiU9tfn(TKv2S%sz zQ@3^YO-xL69_;V$>{{Bfykkk{s?O1o1A;iZYGr=q^2L*b1H*lV#iJu*(?=H{9GkWU zN5=X`rw0a|&grSiP6Kov7%5E6#B>&pO$-7bY;t&DXhmmNN7pj6S&5Y6uta`jY^0Ds zJXq-K=x5ib3IhX!Lmk5ynIlAz#2M&RVRE{^kl)m^Z6gpk?k%QJ13#d-82`p>SwTz} zF`HLROdl8>=|?_zws}QQ5M=#v!sfI^T>_sB}M78c!xn6*sl7IfZ zir=g}ub}XA9)EHkVC%j>zF-#Q)$Cs7qQ*sDy_&0&3y?I}c}TWu>}5zU(8)`YoUfBf zBriF~GRph9s((bOn^cSU7Nu@fjoxo6wOiGBZ&hlS%6e~8%Duf8iQhuvSg&evQ{h`f zNEdoljhpsPB01Ho8r+N|Cwo<$o0a6Py{gr%3-4v&!$j8$dbC$1+@=>)_HN~(@-3<% zyrN!t;m!4mFD(sCt6Dz5#724cs@!{2z1OQ20Svph7F09w7>HZ{0{DZ!PvV~nonLOa zta-1ZUsZ|wA5h7!gWs)>26%{>@j3j3GX4UdeT%B^RWWck>eVW>)%ya-zfrC9ex%eJ z(388#t(E#wubH+|Kk7B_R_aH+X5rE@PA;`9%~+N$vxx@px52BUy`XLqwQgLPb{lZT zWY$dx_6V_lvcXLXcDh$}7L#c=C0IH5|dD zE44?(!t)z2VG!upwD$;kU$Yky`yxT|>b%PBRW%T*d(^C3RO|`0I=sA5#h+A(@U``L zr6zT_(`3C)Hf$Zh=57 zd07OZOGSUAvgqzfmF+~&dKG?VBIb3dd93jUA_X< zIv9GkRPjQ48pVqgTg@N7wad_)(v^oM`wkD{S2u>$w4 zyd*OPXmrpo1}mlWv?{f~1>$By$_+26gN95&89?;fFneyNn$5?M2o8|52)#=+-~kb+ zA5pXa+N)Dh(XC%lsq;#mQZ+ZL+2J3C>QweQHTzuor~8Qa1vC=#KBRIU`Z?tkSK z6@vx}Uj-q55enGbZ!+}b3&jUix+%6d{CTvIInTvX%THwC2O}b(E|uT|I_lIHp|-D5 z&E65UprGovs91-pze=?g)Z#6w>#SO}M%AAyg0U-A@@AB7D3)$sTTIto1r@bbn-!?E z%qiu5N-YYntyi@}=<-&TfH9%X$=$4C1$7Bo)rli^JkF|%`0&;!E=2J0Vm_`^EqH*B zvA3wMy{h(Qm3yU($fYdTsTT5akEXRnL%*2TkA5+&lm91aVP5VBgH-JNr&art3U3pJ zcDpD%uTd>7sHQEx6fN4PmK2n`1%fC#FtbOgg1P`@?@^cbs>~LZI|zBXTP+Q*u2%~o zsncq{H>4I}G+R`%Q!U@CR-IKnz3QqL)WsdD{UCm9a7bP9q`DZ{Yt@{+s{O25-m6w2 zdySgYsoGyqS6``?g3m9gn#HPpSXX#XDs-xO`&6c&E?T2D6x5Q3)#f!6pLuIl=3ydt z^r#JM|9SZJYgOmNs%DjHKPD|*{G3Wo%YqBL{cT!FZxKBke!{Lb*PZ_)7g*?&=+N2l z-onn}YC7~^Ut?DHR!ej!HIS$&aYF-YQLD;Q^{G{*R@ML}2VJp1zsZYrdb-XnO8CKo;(3aPbssRbuh`XuV#il>_nuOzK0NVxkPe%&-0Qf&v7dNDk& zUZw9>ZKq8-^uUjmyWQ*b*82bL@$`Sw#HeNX=l0@p{`DUxbrJjU&fo8y@(%t>{`>!^ zB8G@T;;jt_!!CRbeq|x-bpC&_K8%I_e`tmDU*CEDTnIaN zXb=2arol>FpE)_qoq9;`fhVrC} zpJE!OHU6V=WU#=@bm|m$6WrR#3c5`!%r}4G$p1Bba_v-4OpZ_BtYvy)LVMwrtOwZR zTZ+mYWvu|EQl`SFXr|h?^-|)aaA{>XTu`ZLm3u(d-VNMZ0txJJ@8;$Tok6CA}hmzdVo*;)8U8ZFT(;<%4y*UR2q;RPqt_c?r@VH|Z-t=V8-- zmVa1f9#M&NDztS(c#)!)S`bdu1UPZGf=;;T1v+FXY|KBz-p=H3qiS!BrhNWyER?o-)3^N4R;# zCjaCRC1)rPY>z7_3}8!DFcAHtBPSb1azoIAp-X2X9MhaWa{6_j#F63wdpW(A|EE9?190y?JIyv5nc=yX5Gjc>liS?lHuwY(0aF zS6+F=TZ?10PpV7Lt0uq61Q?0ebVWjYWIaEIsS7*&ide<R z%6cAe#d(N&R?Wjv<%=p4zPM2za6YI{J?cLYYy zoQB5SSubN%oK$T%A$k$5&1+PN+q4j@UGYn_&f}u+jMh7U4XrPi%Z95yr5aDFxlgDX ztQ#II->QRQOz?^^}hhM`XP1UU8?m-RkKY&sgV4Y52=NBso7XRMVu)HT~Nd= ze@M;03&(Ca5%KFTg-X%A^-Z-IrADR-RhT#c?E*+!i&n0Y&fLAX%|Ol93W13kxYf>HK@4{ ztHn5q9pXTttaUon+5K-knZXm;0^Scz8pgXSs@ScPd+Gl}_9|#1f02J0xC;Njbqij0 z^=+L;_ya-bQEt!6Zo!MrD{{3tvu}oRTSIWdrm?I}syRng9j=C7R=C2ZT0aO^XwJfYj_`yo7+G-G~Z2jsJQpyITibaYB{2^yhiWv z??cQb`WICD%_`mt8uu6)y#0mmM|v&$N@}@pRJGxY>UmilJEv;9swUbZrwO2$(x@Czc--s zcXUZH9a^el?E&f`v?{vi_rZm*^K4b!6X3Fmo(ZakUr8GU3H>4+6Wjv__vMat>g`rg zrr%CEW}m8{7++IF{7ZJhK`jHel}ZzYrFgkqqJU=XG)r!=v9YY+p95REKL&y_UUI?) z+~yTUeTFV+1!li~*@_8&MLg`#S-D`wc2vjk?0Zqo`kGn@_Z$Ax9+POr)!$jQY>T@5 zth!2H*`75wxcbW0#g*+ZrAWGCnHR2#g{@ESVm{hd{6F7iXd(|RDc_1T;*rrq1JS;?n zk@s#j$7|~`6<*dAE-)LDN3qz$=jFrfP5Pdc%X&m}NB~bkh1~YDD^w!9xJ5;=!)4eG zhMMt)RpMb4-vhAmX2jb(x%Jd3Uan^L63_d7kdXU+Y{}U`ua4_@Sginr>nLtf;O+$| zsK%`%RQ8B%Blna0!I?+MnHo8*Zr-CB&Z?S|YSB5^v|e?|EAl`z04*F`*4bNB-4-=} z8)gilOkk7@=Q`c9dvqYn$Jk5n6Z|9(aP=SC%l$eD=Kfj&1jxc!-lx>udw4Q1x5tos zSv7+c$b1|}2eBn!z7BKAKdI)B5`wDuI4h$Je^5h)r9)upg=fVI<@4i1L-~S}@7a-; zMKe*Dbn^YfIR0|_ho{F5<@p8j{M7LHWC1}OQV!4jfxf9hXLNk*V4HkQk4=pn92*>H zgJy6Tyq7;XIX*p+pXe(LV?|wygD8~GBe<`yaygpAy3eoA@9N4QL@Of`rKNY~*KgZ} zh?L#yc5U39U$=h!#$CJeJsVK=+U+;Ct?%k;(~*m9iw_s3#|GCP92^^*9O(zxH`zbD z7Ez3gS1xZ`e6VftjwNl2p*Ys|qt4=?zOla1W48}Z2KvqJvM<}$?e4j0V}8Sq8?V{6 z5e*rAGI+Ewh>?wtbL(?4Ld;gIMlD^HEw4&L`qjG|X0 z*pG=TuxpcpgCLmaJPl32;ueOSvFXG4fxZG}3t^gpk#5?yW8H2Hl=FVu0`-2|Tv7T0gOe%2Q1yAJWYDyb zdnLlQ{)Ua~c5l?eHZgK^a5O(KI8hijbDyV)6Zst)9q-eN1~PXDB9+(ADMt@FKQRt@ zxMqBO)bY8AMKy^Acj<9q77tH=JDtPhhX*@v>p!$?)$(O4J2wnY9V(1Zbiy(%9bRE3 zgi@M6Qs_GX1{nD;L}ai$Q5qT<937altk)7gFpePC!Qial*t4CJE^{%_*FWfpfDa5p z0C6TeRp>iBp@&Mb;ljjt1}7(F!S1wc7(Eakz*rl;SluB?fdV6cgJx8jXq+QIrUm|farm~{zFhH(#SB^qgFIV%BHYT z$0zfneaFV9jWGEOVsvCmPnMQ+plL$OG-oM~&KZ*po-qVV+PJbRNbU~ZkM!CR*X z$NC5JnA`&p*+}&LdN?h5P>Lt92gYdLY)a$v{XY%v7DwSp?Dyr`Kh4Vs35^I z;-T@$!&ssIP@I85hz2{&P(;`v@Naso05)j8iC%+5qg>%AKcH{eN3!--C!h+5m@3j; zQcQLglgo<9<;CQRVsd3MdAXU?u9cWn+ds%~*{H{~lAA>5AP^3W#NZ(;fW!UJjK*3) zH%_3>hbPS3I2fu3oyiYcGY&C-)bJjn5m-FVP+@R%RJbUzw^>#(tlmM`a!QkyNTG1d z86O)xCPpzo#>t$RhMkc`u0@(2wvo)iqa#>_`H`vd{?)7VQ&atYV?z$iXgWip|Iq>6<02QaGxbMI_s8j*JlG#Z ziiZHFBR?S;A0+a-*6-N4F~4oc`gPklru-CK2|6&vylc1ZxCWU+#-Gv-6U0XDLA6u` zCqfvUAu1&4if__lf|Pbd(K?hZEZ5-V;lY6s0^+)( z!0!C6-5c^ZcC8eb*oRjx_hI8UYp;R@`YE6^%t0A6ZYr}7@iIzZl_u9Xe5RFEhN$+( z=$z$)&e-M^{lkNh*dv3J^vC_~!>7u_sEuRc9+WPx=bmBX4L9t#!5JuRVcAl@-%{v? zjk`A9aMQ*O`K~3!nnh$+C8T(x`LgQEDwSMO0a>YbrOL}I)U8BsRfTe^Vb~7C3{1(k zWpwb!Al)d<)onf7x0Z1=!0zBii*s2z%9Rz`y1a^LPQ zrjLcjhwRd#3dUZ>SMd7YwLh?);I~a-4Y3=$^1C)}+qiyre&-DvcW&IiA&7!>aU>>K zqF?%A7VH4zJXjR+XtXR|%rSyUNfm#}jZHy30!2pO?OFiN@{oczg>{`F!kCYLRn-PkZTyX5l$=`WB_o7@MO z_5^F#)3g1ib=!K#o(){$y1#_jy4}@TUal+Um#Q5$`%jE8-*0qmfE{m^Q~+pyyqOvRl>)e$1CC!&d%CO<&(~m zrb_sfv$G;T?L5$0seH!q?x}>&I?WaFIp@qLDwVHs9)GkFzSep5Q~RCrKi8>qUaN?& zcbrdGD&OF|`k6}jM!W~U628fK{Iiwt&CW{|@qEe4%sC8&~PvTCn68^F(c)panQu*O3c)t9-Qu(t6Up`*`U<%9sxQq{fQ3d}~gD>Y#Bd&rf z@wr_t`_j%!W%DxM;B&LO(ShRMN`v27hTjH!$Z2*y`pkYQOtIl#ui$6uPyR|l*hxEg zmeJuaR)n0HdiZ0&SL*-yD)^_X;QzD=os_ zORM0k%_DzlG33-Zqkq^fd=Gw9>d!SOkN1wuu#Yziotbv(kd&{TVF&Lp_;S1XE}=8i zKCZwUUc=5zf8ZXxqqEJKX$S8Eom$9=jlh^=1nWN-{GA)RWvJiAOI!K(oWa|#YT(@# z^2gt(sx|50<3%YS#OU;2Rl$GP&@cZ%jMu7^PeyhB9iy*MO#WsG-T;9|mnmQV8;2XJ zlz$`eHCT7nPXHU`?>$J6Z&n|68vN~s{>}Tl1+&+5=u{Q@?=a<`UZTtY6JY)gV;)Jr z{I?wMt3u~Pz_&@w(vL^0lz+Mko<&QtU zLpt4MbiQct`^)fuBXo4#;3t2@wi18%3sIHu{867u_ytBj%ilwO1@JZawIJ)yL(R%x zPZc`5tKf&L;BT*je<$#{3i{^*Qau(GiYF7%rgtP$HRl(n6=-6*@{W<*) z{0$j=`ESGCVep%8>XvfLjQ)8K@RZLx%jEFiOL-|;^6?2nr~LKmpRZD$ZxQEux8JXP z#R%4a2R?^(%lY{eQ@;GSf0KB5ekFOHTLr%qc#i9VvT?1iQhpop@b|3$Z0*H>lutY5 zKX&yShW=A!^xtFfFO}i>t9X_A|Cpg~zoGqEV^5!{Ql8&`C*K}@W`D`Ne8tcy|Apf3 zSD^z}K<359)2%YpvVt!mEx@cQ_$5{F8x4K?wv97}q1RU_e>3o$FXx&4(jJzZ{EZnp zFU{)~_^Z%^{JX0Pop%~KZO`myG5mmx{ySTxJbztS^z$?OrJybURF(4owF>?f!NadU z+%0tYgKYf!2Sb1VGy4hp{mE4Ei}=%3vL2t=&*FahrNC29mamu9Rp@N5g5OgGe>?E9 zUY^;{X8m@5t4jGZf=~NDsAYd&;4y=@-_4?(lRtS`SVspRE0=fnPZqj5#+{D7v9a+3 zxDVnD4Ni5-V4Tnol;b*v#|z~+maByCm>wG)IW#zWtYU>~nH_S}IXzLaQkA?8xumSn z{jv;HFO2l#CLGsj!SR;jOUGTBS31tpyqSC`&9A_Z(gH$YCSOVm&E!vMz7PRwvJm89 zX_?n$ix4PfXntT+GmZC5hSbE!pzca>qN)|691V^R;oWW!v+-TU3P8?~y&{essZ_Rf z4ob^c%d5cqvWheLUMw(^=f%9r{4VB~@w%8%iO+eg&wgCTO>4HuG!|KqFUv0BPaty$ zjGi$!#k!Ksx=;gC1zbjADIkUiH^Wo7PRth&Lxku+1dZhL1LOIFqvHo~gEN5Zm8pE+ z^ijE}8pWmMK*y5GC2*rNHlnXQFvh~9e|0{6`0z1QF_+?mWSAvIXGG8Oo)sPBMTrS8 zU@{OyP<&4nO3k?b*O&VhE^GaUNF3GdrILR+l+SOvVcm5b^SDFG=h1CMG3GaJHptBz zZgBGY4m!VM(c$`(r|wVGyBbG{0fb_I20wtbd(b@XEm$Wl<5hhV$=* zb+ldC#hJu}ba!97t>>Ec`K298J651OzKn66{NS$AQkLC;Yw_y$TlS)|QtYQ6xKX^r zmdOwy;2n|<7s%%i9!9*Tum{{`JW6SYByy${RTh*|%)A^yI3tB3%wcmMSE=GFvwVu|SJ9WxaYXj2kR1YKC#mtr)a z)`%F(fhoMhM6QeFdcHhN5lrbnR7#}s{jo23HcrHbgI9J2>}`B`bdZ%-i47?YR;U`@ zAfZIXp-G^lS+IeS1AllnN=Jfe5fVg+Dji{2xEol{J8ua!fbcN9tF*jnjIqBkVJ1#R z^p=T=0|hNzI{dY?wvjTfB)g`4f(#(%%u9@pAKPMrrb>7fT-ZYr8&KK`sFVh~7VTn* z*7oPo50lryVl$|f#0}*K*>xL`US2j3<^9XXBk4#X9r{=#haeFn?Aj{`NV~+hja}S>mfC48ie}}k6?p! zkh>>*bVvi57}l%Pf#{#Z@Rf8Y4@{4Y4s`St5cP5Z5i-agz^gb9f?6M<_>Df4#$4&kF%!HTo-;V!QQ~w%6(8kN`G>398nR#G+#!8g)?>B&B6Nb%x zT+I^v>K*^eBR%ZA>s-ehCP$zZn+JeDvR4W%VCu?UsxOT6O;5w0_!8 zThGF8MIzX~jpy<1(IwKhpm~<}{~e~j<-ffrXg2jvm4%{M{#mlWTUOu32c7wZE-{;( z3;dP0{}A$6#I|qah#r4bS9-jxLV5e=P%MLgmd*Cw^wm%4`sL*YA9y~(`1&HZKzWJ zbAP2Pyf1GmR;k}!rT*S^x}`XN{Ui9Nu| Date: Thu, 24 Apr 2025 09:44:40 +0100 Subject: [PATCH 045/251] Remove blosc.h --- src/framebuffer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index 07173e8..1d8f1a2 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -16,7 +16,6 @@ #include "mib_header.h" #include "utils.h" -#include #include #include #include From 688c07633e2ef0dd744db595232d2f749d50c1ca Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 24 Apr 2025 09:48:24 +0100 Subject: [PATCH 046/251] Remove include drectory in config.mk --- config.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.mk b/config.mk index 89b0dee..c04ba0c 100644 --- a/config.mk +++ b/config.mk @@ -1,7 +1,6 @@ # === Directories === SRCDIR := src OBJDIR := obj -INCDIR := include HDFDIR ?= $(HDF5_ROOT) BUILD ?= debug @@ -24,7 +23,7 @@ else $(error Unknown BUILD type: $(BUILD)) endif -CFLAGS += -I$(SRCDIR) -I$(INCDIR) -I$(HDFDIR)/include +CFLAGS += -I$(SRCDIR) -I$(HDFDIR)/include LDFLAGS += -L$(HDFDIR)/lib -lhdf5 # === Sources === From e4902b66cfef1872cbdad350f3c9099b6f764b71 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 14:51:03 +0100 Subject: [PATCH 047/251] Add files for initializing hdf5 --- src/hdf5_init.c | 177 ++++++++++++++++++++++++++ src/hdf5_init.h | 32 +++++ src/hdf5_init_meta.c | 294 +++++++++++++++++++++++++++++++++++++++++++ src/hdf5_init_meta.h | 23 ++++ 4 files changed, 526 insertions(+) create mode 100644 src/hdf5_init.c create mode 100644 src/hdf5_init.h create mode 100644 src/hdf5_init_meta.c create mode 100644 src/hdf5_init_meta.h diff --git a/src/hdf5_init.c b/src/hdf5_init.c new file mode 100644 index 0000000..0194f01 --- /dev/null +++ b/src/hdf5_init.c @@ -0,0 +1,177 @@ +#include "hdf5_init.h" +#include "blosc_filter.h" + +#include +#include +#include +#include +#include +#include + +/* +// functions for debugging +void check_space_and_storage(hid_t dset) { + H5D_space_status_t space_status; + hsize_t storage_size; + + status = H5Dget_space_status(dset, &space_status); + storage_size = H5Dget_storage_size(dset); + printf("Space for dataset has%sbeen allocated. \n", space_status == +H5D_SPACE_STATUS_ALLOCATED ? " " : " NOT "); printf("Storage size for dataset is +: %ld bytes.\n", (long)storage_size); +} +*/ + +// REAL functions +void initialize_file_and_plist(char *filename, + hid_t *file_id, + hid_t *fapl_id, + hid_t *fcpl_id) +{ + unsigned mode = H5F_ACC_TRUNC; + char *version, *date; + + if ((*fcpl_id = H5Pcreate(H5P_FILE_CREATE)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating fcpl in create_file\n"); + return; + } + if ((*fapl_id = H5Pcreate(H5P_FILE_ACCESS)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating fapl in create_file\n"); + return; + } else { + if (H5Pset_alignment(*fapl_id, 1024, 4096) < 0) { + fprintf(stderr, "Error in H5Pset_alignment\n"); + return; + } + } + if ((*file_id = H5Fcreate(filename, mode, *fcpl_id, *fapl_id)) == + H5I_INVALID_HID) { + fprintf(stderr, "Error in creating file_id in create_file, please check if " + "file already existed\n"); + return; + } + if (register_blosc(&version, &date) < 0) { + fprintf(stderr, "Error in register_blosc\n"); + return; + } else { + printf("Blosc version info: %s (%s)\n", version, date); + free(version); + free(date); + } +} + +void initialize_lcpl(hid_t *lcpl_id) +{ + if ((*lcpl_id = H5Pcreate(H5P_LINK_CREATE)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating lcpl in initialize_dataset_plist\n"); + return; + } + /* + else { + if (H5Pset_create_intermediate_group(*lcpl_id, 1) < 0) { + fprintf(stderr, "Error in H5Pset_create_intermediate_group\n"); + return; + } + if (H5Pset_char_encoding(*lcpl_id, H5T_CSET_UTF8) < 0) { + fprintf(stderr, "Error in H5Pset_char_encoding\n"); + return; + } + } + */ +} + +void create_merlin_dataset(hid_t *merlin_dataset_id, + hid_t *file_id, + char *merlin_dataset_name, + int dtype, + hid_t memspace, + hid_t *lcpl_id, + size_t dim, + hsize_t *frame_dim, + unsigned int compression_level, + unsigned int shuffle, + unsigned int compressor) +{ + hid_t file = *file_id; + hid_t lcpl = *lcpl_id; + hid_t dcpl; + hid_t dapl; + // int fill_value = -1; + unsigned int cd_values[7] = {0}; + + if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating dcpl\n"); + return; + } else { + if (H5Pset_chunk(dcpl, dim, frame_dim) < 0) { + fprintf(stderr, "Error in H5Pset_chunk\n"); + return; + } + if (H5Pset_fill_time(dcpl, H5D_FILL_TIME_NEVER) < 0) { + fprintf(stderr, "Error in H5Pset_fill_time\n"); + return; + } + /* + if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fill_value) < 0) { + fprintf(stderr, "Error in H5Pset_fill_value\n"); + return; + } + */ + cd_values[0] = 0; + cd_values[1] = compression_level; + cd_values[2] = shuffle; + cd_values[3] = 0; // blocksize + cd_values[4] = 0; // unused + cd_values[5] = 0; // unused + cd_values[6] = compressor; + if (H5Pset_filter(dcpl, FILTER_BLOSC, H5Z_FLAG_OPTIONAL, 7, cd_values) < + 0) { + fprintf(stderr, "Error in H5Pset_filter\n"); + return; + } + } + + if ((dapl = H5Pcreate(H5P_DATASET_ACCESS)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating dapl_id\n"); + return; + } else { + unsigned int y = frame_dim[1]; + unsigned int x = frame_dim[2]; + + if (H5Pset_chunk_cache(dapl, 521, 2 * dtype * y * x, 1.0) < 0) { + fprintf(stderr, "Error in H5Pset)chunk_cache\n"); + return; + } + } + + hid_t datatype; + switch (dtype) { + case 1: { + datatype = H5T_STD_U8LE; + break; + } + case 2: { + datatype = H5T_STD_U16LE; + break; + } + case 4: { + datatype = H5T_STD_U32LE; + break; + } + case 8: { + datatype = H5T_STD_U64LE; + break; + } + default: { + fprintf(stderr, "Error in datatype, please check input dtype\n"); + return; + } + } + + if ((*merlin_dataset_id = H5Dcreate2(file, merlin_dataset_name, datatype, + memspace, lcpl, dcpl, dapl)) == + H5I_INVALID_HID) { + fprintf(stderr, "Error in creating merlin_dataset\n"); + return; + } +} diff --git a/src/hdf5_init.h b/src/hdf5_init.h new file mode 100644 index 0000000..6b917e5 --- /dev/null +++ b/src/hdf5_init.h @@ -0,0 +1,32 @@ +// clang-format Language: C +#ifndef HDF5_INIT_H +#define HDF5_INIT_H + +#include +#include +#include +#include +#include + +void check_space_and_storage(hid_t dset); + +void initialize_file_and_plist(char *filename, + hid_t *file_id, + hid_t *fapl_id, + hid_t *fcpl_id); + +void initialize_lcpl(hid_t *lcpl_id); + +void create_merlin_dataset(hid_t *merlin_dataset_id, + hid_t *file_id, + char *merlin_dataset_name, + int dtype, + hid_t memspace, + hid_t *lcpl_id, + size_t dim, + hsize_t *frame_dim, + unsigned int compression_level, + unsigned int shuffle, + unsigned int compressor); + +#endif diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c new file mode 100644 index 0000000..016a925 --- /dev/null +++ b/src/hdf5_init_meta.c @@ -0,0 +1,294 @@ +#include "hdf5_init_meta.h" +#include "macros.h" + +#include +#include +#include +#include +#include + +void create_meta_mq1_fields_dataset(hid_t *file_id, + hid_t *lcpl_id, + hid_t *meta_handle) +{ + if (meta_handle == NULL) { + fprintf(stderr, "meta_handle is NULL in create_meta_fields_dataset\n"); + return; + } + + hid_t file = *file_id; + hid_t lcpl = *lcpl_id; + + char meta_group_path[64] = "metadata"; + hid_t meta_group = + H5Gcreate(file, meta_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); + if (meta_group < 0) { + fprintf(stderr, "Error creating group in create_meta_mq1_fields_dataset\n"); + return; + } + + hsize_t dim[1] = {0}; + hsize_t max_dim[1] = {H5S_UNLIMITED}; + hsize_t chunk_dim[1] = {1}; + + hid_t dataspace = H5Screate_simple(1, dim, max_dim); + if (dataspace < 0) { + fprintf(stderr, + "Error creating dataspace in create_meta_mq1_fields_dataset\n"); + return; + } + + hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); + if (dcpl < 0) { + fprintf(stderr, "Error creating dcpl in create_meta_mq1_fields_dataset\n"); + H5Sclose(dataspace); + H5Gclose(meta_group); + return; + } else { + if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { + fprintf(stderr, + "Error setting chunking in create_meta_mq1_fields_dataset\n"); + H5Pclose(dcpl); + H5Sclose(dataspace); + H5Gclose(meta_group); + return; + } + } + + hid_t dapl = H5Pcreate(H5P_DATASET_ACCESS); + if (dapl < 0) { + fprintf(stderr, + "Error in creating dapl in create_meta_mq1_fields_dataset\n"); + H5Pclose(dcpl); + H5Sclose(dataspace); + H5Gclose(meta_group); + return; + } else { + } + + // hid_t header_id_type = H5Tcopy(H5T_C_S1); + // H5Tset_size(header_id_type, MQ1_CHAR_LEN_HEADER_ID); + + hid_t pixel_depth_type = H5Tcopy(H5T_C_S1); + H5Tset_size(pixel_depth_type, MQ1_CHAR_LEN_PIXEL_DEPTH); + + hid_t sensor_layout_type = H5Tcopy(H5T_C_S1); + H5Tset_size(sensor_layout_type, MQ1_CHAR_LEN_SENSOR_LAYOUT); + + hid_t chip_select_type = H5Tcopy(H5T_C_S1); + H5Tset_size(chip_select_type, MQ1_CHAR_LEN_CHIP_SELECT); + + hid_t timestamp_type = H5Tcopy(H5T_C_S1); + H5Tset_size(timestamp_type, MQ1_CHAR_LEN_TIMESTAMP); + + hid_t header_extension_id_type = H5Tcopy(H5T_C_S1); + H5Tset_size(header_extension_id_type, MQ1_CHAR_LEN_HEADER_EXTENSION_ID); + + hid_t extended_timestamp_type = H5Tcopy(H5T_C_S1); + H5Tset_size(extended_timestamp_type, MQ1_CHAR_LEN_EXTENDED_TIMESTAMP); + + hsize_t threshold_dims[1] = {MQ1_FLOAT_LEN_THRESHOLD}; + hid_t threshold_type = H5Tarray_create(H5T_NATIVE_FLOAT, 1, threshold_dims); + + struct { + const char *name; + hid_t type; + } fields[] = { + //{"header_id", header_id_type}, + {"max_length", H5T_NATIVE_UINT}, + {"sequence_number", H5T_NATIVE_UINT}, + {"header_bytes", H5T_NATIVE_UINT}, + {"num_chips", H5T_NATIVE_UINT}, + {"det_x", H5T_NATIVE_UINT}, + {"det_y", H5T_NATIVE_UINT}, + {"pixel_depth", pixel_depth_type}, + {"sensor_layout", sensor_layout_type}, + {"chip_select", chip_select_type}, + {"timestamp", timestamp_type}, + {"exposure_time_s", H5T_NATIVE_DOUBLE}, + {"counter", H5T_NATIVE_UINT}, + {"colour_mode", H5T_NATIVE_UINT}, + {"gain_mode", H5T_NATIVE_UINT}, + {"threshold", threshold_type}, + {"header_extension_id", header_extension_id_type}, + {"extended_timestamp", extended_timestamp_type}, + {"exposure_time_ns", H5T_NATIVE_UINT}, + {"bit_depth", H5T_NATIVE_UINT}, + }; + + size_t num_datasets = sizeof(fields) / sizeof(fields[0]); + + for (size_t i = 0; i < num_datasets; i++) { + char dataset_path[256]; + // snprintf(dataset_path, sizeof(dataset_path), "metadata/%s", + // fields[i].name); + + snprintf(dataset_path, sizeof(dataset_path), "%s", fields[i].name); + + hid_t dataset = H5Dcreate2(meta_group, dataset_path, fields[i].type, + dataspace, lcpl, dcpl, dapl); + if (dataset < 0) { + fprintf(stderr, "Error creating dataset : %s\n", dataset_path); + meta_handle[i] = -1; + continue; + } + + meta_handle[i] = dataset; + } + + // H5Tclose(header_id_type); + H5Tclose(pixel_depth_type); + H5Tclose(sensor_layout_type); + H5Tclose(chip_select_type); + H5Tclose(timestamp_type); + H5Tclose(header_extension_id_type); + H5Tclose(extended_timestamp_type); + H5Tclose(threshold_type); + + H5Pclose(dcpl); + H5Pclose(dapl); + H5Sclose(dataspace); + H5Gclose(meta_group); +} + +void create_dac_dataset(unsigned int num_chips, + hid_t *file_id, + hid_t *lcpl_id, + hid_t *dac_handle) +{ + if (dac_handle == NULL) { + fprintf(stderr, "dac_handle is NULL in create_dac_meta_dataset\n"); + return; + } + + hid_t file = *file_id; + hid_t lcpl; + if (lcpl_id == NULL) { + lcpl = H5P_DEFAULT; + } else { + lcpl = *lcpl_id; + } + char chip_group_path[256]; + char dataset_path[512]; + hid_t chip_group; + hsize_t dim[1] = {0}; + hsize_t max_dim[1] = {H5S_UNLIMITED}; + hsize_t chunk_dim[1] = {1}; + hid_t dataspace; + hid_t dataset; + + hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); + if (dcpl < 0) { + fprintf(stderr, "Error creating dcpl in create_dac_dataset\n"); + return; + } else { + if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { + fprintf(stderr, "Error setting chunking in create_dac_dataset\n"); + H5Pclose(dcpl); + return; + } + } + + hid_t dapl = H5Pcreate(H5P_DATASET_ACCESS); + if (dapl < 0) { + fprintf(stderr, "Error creating dapl in create_dac_dataset\n"); + H5Pclose(dcpl); + return; + } else { + // modify dapl if needed + } + + hid_t str_type = H5Tcopy(H5T_C_S1); + if (H5Tset_size(str_type, 4) < 0) { + fprintf(stderr, "Error setting string type size in create_dac_dataset\n"); + H5Tclose(str_type); + H5Pclose(dcpl); + H5Pclose(dapl); + return; + } + + struct { + const char *name; + hid_t type; + } datasets[] = { + {"dac_format", str_type}, {"threshold0", H5T_NATIVE_UINT}, + {"threshold1", H5T_NATIVE_UINT}, {"threshold2", H5T_NATIVE_UINT}, + {"threshold3", H5T_NATIVE_UINT}, {"threshold4", H5T_NATIVE_UINT}, + {"threshold5", H5T_NATIVE_UINT}, {"threshold6", H5T_NATIVE_UINT}, + {"threshold7", H5T_NATIVE_UINT}, {"preamp", H5T_NATIVE_UINT}, + {"ikrum", H5T_NATIVE_UINT}, {"shaper", H5T_NATIVE_UINT}, + {"disc", H5T_NATIVE_UINT}, {"disc_LS", H5T_NATIVE_UINT}, + {"shaper_test", H5T_NATIVE_UINT}, {"dac_disc_L", H5T_NATIVE_UINT}, + {"dac_test", H5T_NATIVE_UINT}, {"dac_disc_H", H5T_NATIVE_UINT}, + {"delay", H5T_NATIVE_UINT}, {"TP_buff_in", H5T_NATIVE_UINT}, + {"TP_buff_out", H5T_NATIVE_UINT}, {"RPZ", H5T_NATIVE_UINT}, + {"GND", H5T_NATIVE_UINT}, {"TP_ref", H5T_NATIVE_UINT}, + {"FBK", H5T_NATIVE_UINT}, {"Cas", H5T_NATIVE_UINT}, + {"TP_ref_A", H5T_NATIVE_UINT}, {"TP_ref_B", H5T_NATIVE_UINT}}; + + size_t num_datasets = sizeof(datasets) / sizeof(datasets[0]); + int handle_pos = 0; + + for (unsigned int i = 0; i < num_chips; i++) { + snprintf(chip_group_path, sizeof(chip_group_path), "metadata/Chip%02d", i); + + chip_group = + H5Gcreate(file, chip_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); + if (chip_group < 0) { + fprintf(stderr, "Error creating group chip%02d in create_dac_dataset\n", + i); + H5Tclose(str_type); + H5Pclose(dcpl); + H5Pclose(dapl); + return; + } + + dataspace = H5Screate_simple(1, dim, max_dim); + if (dataspace < 0) { + fprintf(stderr, "Error creating dataspace in create_dac_meta_dataset\n"); + H5Tclose(str_type); + H5Pclose(dcpl); + H5Pclose(dapl); + H5Gclose(chip_group); + return; + } + + handle_pos = num_datasets * (size_t) i; + + for (size_t j = handle_pos; j < (handle_pos + num_datasets); j++) { + // snprintf(dataset_path, sizeof(dataset_path), "%s/%s", chip_group_path, + // datasets[j-handle_pos].name); + + snprintf(dataset_path, sizeof(dataset_path), "%s", + datasets[j - handle_pos].name); + + dataset = + H5Dcreate2(chip_group, dataset_path, datasets[j - handle_pos].type, + dataspace, lcpl, dcpl, dapl); + if (dataset < 0) { + fprintf(stderr, "Error creating dataset: %s\n", dataset_path); + dac_handle[j] = H5I_INVALID_HID; + continue; + } + dac_handle[j] = dataset; + } + + H5Sclose(dataspace); + H5Gclose(chip_group); + } + + H5Tclose(str_type); + H5Pclose(dcpl); + H5Pclose(dapl); +} + +void close_dataset_handle(hid_t *handle, size_t count) +{ + if (!handle) + return; + for (size_t i = 0; i < count; i++) { + if (handle[i] >= 0) { + H5Dclose(handle[i]); + } + } +} diff --git a/src/hdf5_init_meta.h b/src/hdf5_init_meta.h new file mode 100644 index 0000000..946f939 --- /dev/null +++ b/src/hdf5_init_meta.h @@ -0,0 +1,23 @@ +// clang-format Language: C +#ifndef HDF5_INIT_META_H +#define HDF5_INIT_META_H + +#include "macros.h" +#include +#include +#include +#include +#include + +void create_meta_mq1_fields_dataset(hid_t *file_id, + hid_t *lcpl_id, + hid_t *meta_handle); + +void create_dac_dataset(unsigned int num_chips, + hid_t *file_id, + hid_t *lcpl_id, + hid_t *dac_handle); + +void close_dataset_handle(hid_t *handle, size_t count); + +#endif From e0c6c235a370b0bdd8529ecb3d0bcf12a4927c54 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 22 Apr 2025 16:26:26 +0100 Subject: [PATCH 048/251] Comment out debug functions in hdf5_init.h --- src/hdf5_init.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 6b917e5..f365b39 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -8,7 +8,7 @@ #include #include -void check_space_and_storage(hid_t dset); +// void check_space_and_storage(hid_t dset); void initialize_file_and_plist(char *filename, hid_t *file_id, From 94a37c0368d487ded18911c70d26c91f026461e3 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 13:04:48 +0100 Subject: [PATCH 049/251] Change checking in close_handle --- src/hdf5_init_meta.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 016a925..4754a46 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -270,6 +270,9 @@ void create_dac_dataset(unsigned int num_chips, dac_handle[j] = H5I_INVALID_HID; continue; } + // else { + // printf("Created dataset: %s\n", dataset_path); + // } dac_handle[j] = dataset; } @@ -284,10 +287,12 @@ void create_dac_dataset(unsigned int num_chips, void close_dataset_handle(hid_t *handle, size_t count) { - if (!handle) + if (!handle) { + printf("No handle\n"); return; + } for (size_t i = 0; i < count; i++) { - if (handle[i] >= 0) { + if (H5Iis_valid(handle[i])) { H5Dclose(handle[i]); } } From cfef2ac7cdece8d349eeae19bc7714199c693802 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Fri, 25 Apr 2025 11:49:12 +0100 Subject: [PATCH 050/251] Remove extra comment in hdf5_init --- src/hdf5_init.c | 16 ---------------- src/hdf5_init.h | 2 -- 2 files changed, 18 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 0194f01..bab9711 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -1,6 +1,5 @@ #include "hdf5_init.h" #include "blosc_filter.h" - #include #include #include @@ -8,21 +7,6 @@ #include #include -/* -// functions for debugging -void check_space_and_storage(hid_t dset) { - H5D_space_status_t space_status; - hsize_t storage_size; - - status = H5Dget_space_status(dset, &space_status); - storage_size = H5Dget_storage_size(dset); - printf("Space for dataset has%sbeen allocated. \n", space_status == -H5D_SPACE_STATUS_ALLOCATED ? " " : " NOT "); printf("Storage size for dataset is -: %ld bytes.\n", (long)storage_size); -} -*/ - -// REAL functions void initialize_file_and_plist(char *filename, hid_t *file_id, hid_t *fapl_id, diff --git a/src/hdf5_init.h b/src/hdf5_init.h index f365b39..91093ce 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -8,8 +8,6 @@ #include #include -// void check_space_and_storage(hid_t dset); - void initialize_file_and_plist(char *filename, hid_t *file_id, hid_t *fapl_id, From 8cee8812096b6d354062ba1ad61dedb5eb025ecf Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 14:25:03 +0100 Subject: [PATCH 051/251] Refactored initialize plist and file --- src/hdf5_init.c | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index bab9711..c2821a0 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -7,14 +7,12 @@ #include #include -void initialize_file_and_plist(char *filename, - hid_t *file_id, - hid_t *fapl_id, - hid_t *fcpl_id) +void initialize_plist(char *filename, + hid_t *file_id, + hid_t *fapl_id, + hid_t *fcpl_id, + hid_t *lcpl_id) { - unsigned mode = H5F_ACC_TRUNC; - char *version, *date; - if ((*fcpl_id = H5Pcreate(H5P_FILE_CREATE)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating fcpl in create_file\n"); return; @@ -34,34 +32,26 @@ void initialize_file_and_plist(char *filename, "file already existed\n"); return; } - if (register_blosc(&version, &date) < 0) { - fprintf(stderr, "Error in register_blosc\n"); + if ((*lcpl_id = H5Pcreate(H5P_LINK_CREATE)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating lcpl in initialize_dataset_plist\n"); return; - } else { - printf("Blosc version info: %s (%s)\n", version, date); - free(version); - free(date); } } -void initialize_lcpl(hid_t *lcpl_id) +void initialize_file(char *filename, + hid_t *file_id, + hid_t fapl, + hid_t fcpl) { - if ((*lcpl_id = H5Pcreate(H5P_LINK_CREATE)) == H5I_INVALID_HID) { - fprintf(stderr, "Error in creating lcpl in initialize_dataset_plist\n"); + if (!H5Iis_valid(fapl) || !H5Iis_valid(fcpl)) { + fprintf(stderr, "fapl or fcpl is invalid in initialize_file\n"); return; } - /* - else { - if (H5Pset_create_intermediate_group(*lcpl_id, 1) < 0) { - fprintf(stderr, "Error in H5Pset_create_intermediate_group\n"); - return; - } - if (H5Pset_char_encoding(*lcpl_id, H5T_CSET_UTF8) < 0) { - fprintf(stderr, "Error in H5Pset_char_encoding\n"); - return; - } + + if ((*file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating file_id in intialize_file\n"); + return; } - */ } void create_merlin_dataset(hid_t *merlin_dataset_id, From e83f12d15fd713c714adf9538c712e08a0ec8bcc Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 14:31:26 +0100 Subject: [PATCH 052/251] Remove commented out code --- src/hdf5_init.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index c2821a0..199d1d2 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -70,7 +70,6 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t lcpl = *lcpl_id; hid_t dcpl; hid_t dapl; - // int fill_value = -1; unsigned int cd_values[7] = {0}; if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { @@ -85,12 +84,6 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, fprintf(stderr, "Error in H5Pset_fill_time\n"); return; } - /* - if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fill_value) < 0) { - fprintf(stderr, "Error in H5Pset_fill_value\n"); - return; - } - */ cd_values[0] = 0; cd_values[1] = compression_level; cd_values[2] = shuffle; From faeef66bee14b3e984ca0ba81d6ea56ae0d3745e Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 14:46:55 +0100 Subject: [PATCH 053/251] Fix clang-format --- src/hdf5_init.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 199d1d2..86b71cf 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -38,17 +38,15 @@ void initialize_plist(char *filename, } } -void initialize_file(char *filename, - hid_t *file_id, - hid_t fapl, - hid_t fcpl) +void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) { if (!H5Iis_valid(fapl) || !H5Iis_valid(fcpl)) { fprintf(stderr, "fapl or fcpl is invalid in initialize_file\n"); return; } - if ((*file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) == H5I_INVALID_HID) { + if ((*file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) == + H5I_INVALID_HID) { fprintf(stderr, "Error in creating file_id in intialize_file\n"); return; } From e7f30e4d1f6e8f71364dfdd7433ba233a1ca633d Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 18:31:17 +0100 Subject: [PATCH 054/251] Remove blosc related code --- src/hdf5_init.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 86b71cf..4e88180 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -2,7 +2,6 @@ #include "blosc_filter.h" #include #include -#include #include #include #include @@ -26,12 +25,6 @@ void initialize_plist(char *filename, return; } } - if ((*file_id = H5Fcreate(filename, mode, *fcpl_id, *fapl_id)) == - H5I_INVALID_HID) { - fprintf(stderr, "Error in creating file_id in create_file, please check if " - "file already existed\n"); - return; - } if ((*lcpl_id = H5Pcreate(H5P_LINK_CREATE)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating lcpl in initialize_dataset_plist\n"); return; @@ -82,18 +75,6 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, fprintf(stderr, "Error in H5Pset_fill_time\n"); return; } - cd_values[0] = 0; - cd_values[1] = compression_level; - cd_values[2] = shuffle; - cd_values[3] = 0; // blocksize - cd_values[4] = 0; // unused - cd_values[5] = 0; // unused - cd_values[6] = compressor; - if (H5Pset_filter(dcpl, FILTER_BLOSC, H5Z_FLAG_OPTIONAL, 7, cd_values) < - 0) { - fprintf(stderr, "Error in H5Pset_filter\n"); - return; - } } if ((dapl = H5Pcreate(H5P_DATASET_ACCESS)) == H5I_INVALID_HID) { From 674cd11702c5eaebe935c2715181b423051519ad Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 18:44:34 +0100 Subject: [PATCH 055/251] Remove more blosc code --- src/hdf5_init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 4e88180..f67544d 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -1,6 +1,4 @@ #include "hdf5_init.h" -#include "blosc_filter.h" -#include #include #include #include @@ -61,7 +59,6 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t lcpl = *lcpl_id; hid_t dcpl; hid_t dapl; - unsigned int cd_values[7] = {0}; if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating dcpl\n"); From 8735420e75ab22255e7c45198d69fbd14d5184d6 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 10:35:29 +0100 Subject: [PATCH 056/251] Changes to references in initialize_plist and initialize_file --- src/hdf5_init.c | 3 +-- src/hdf5_init.h | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index f67544d..efd53ad 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -4,8 +4,7 @@ #include #include -void initialize_plist(char *filename, - hid_t *file_id, +void initialize_plist(hid_t *file_id, hid_t *fapl_id, hid_t *fcpl_id, hid_t *lcpl_id) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 91093ce..22f858e 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -8,12 +8,12 @@ #include #include -void initialize_file_and_plist(char *filename, - hid_t *file_id, - hid_t *fapl_id, - hid_t *fcpl_id); +void initialize_plist(hid_t *file_id, + hid_t *fapl_id, + hid_t *fcpl_id, + hid_t *lcpl_id); -void initialize_lcpl(hid_t *lcpl_id); +void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl); void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t *file_id, From 969335a0e5c6e861308e777bb69882aafcc3c367 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 11:02:33 +0100 Subject: [PATCH 057/251] Modifying references in create_merlin_dataset --- src/hdf5_init.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index efd53ad..3318682 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -43,19 +43,14 @@ void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) } void create_merlin_dataset(hid_t *merlin_dataset_id, - hid_t *file_id, + hid_t file, char *merlin_dataset_name, int dtype, hid_t memspace, - hid_t *lcpl_id, + hid_t lcpl, size_t dim, - hsize_t *frame_dim, - unsigned int compression_level, - unsigned int shuffle, - unsigned int compressor) + hsize_t *frame_dim) { - hid_t file = *file_id; - hid_t lcpl = *lcpl_id; hid_t dcpl; hid_t dapl; From 7cc698df9e63ab0f6bb96524d023f85a63826d9e Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 11:03:28 +0100 Subject: [PATCH 058/251] Modifying references in header file for create_merlin_dataset --- src/hdf5_init.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 22f858e..5df4bc3 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -16,15 +16,12 @@ void initialize_plist(hid_t *file_id, void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl); void create_merlin_dataset(hid_t *merlin_dataset_id, - hid_t *file_id, + hid_t file, char *merlin_dataset_name, int dtype, hid_t memspace, - hid_t *lcpl_id, + hid_t lcpl, size_t dim, - hsize_t *frame_dim, - unsigned int compression_level, - unsigned int shuffle, - unsigned int compressor); + hsize_t *frame_dim); #endif From 69294f0ac2eeb81ab92537c722976eda7756bf91 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 11:11:27 +0100 Subject: [PATCH 059/251] Create function bufsize_to_datatype to handle logic related to different data size --- src/hdf5_init.c | 52 +++++++++++++++++++++++++++---------------------- src/hdf5_init.h | 4 ++-- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 3318682..5323557 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -42,6 +42,34 @@ void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) } } +hid_t bufsize_to_datatype(int dtype) +{ + hid_t datatype; + switch (dtype) { + case 1: { + datatype = H5T_STD_U8LE; + break; + } + case 2: { + datatype = H5T_STD_U16LE; + break; + } + case 4: { + datatype = H5T_STD_U32LE; + break; + } + case 8: { + datatype = H5T_STD_U64LE; + break; + } + default: { + fprintf(stderr, "Error in datatype, please check input dtype\n"); + return; + } + } + return datatype; +} + void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, @@ -81,29 +109,7 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, } } - hid_t datatype; - switch (dtype) { - case 1: { - datatype = H5T_STD_U8LE; - break; - } - case 2: { - datatype = H5T_STD_U16LE; - break; - } - case 4: { - datatype = H5T_STD_U32LE; - break; - } - case 8: { - datatype = H5T_STD_U64LE; - break; - } - default: { - fprintf(stderr, "Error in datatype, please check input dtype\n"); - return; - } - } + hid_t datatype = bufsize_to_datatype(dtype); if ((*merlin_dataset_id = H5Dcreate2(file, merlin_dataset_name, datatype, memspace, lcpl, dcpl, dapl)) == diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 5df4bc3..be57c2b 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -3,10 +3,8 @@ #define HDF5_INIT_H #include -#include #include #include -#include void initialize_plist(hid_t *file_id, hid_t *fapl_id, @@ -15,6 +13,8 @@ void initialize_plist(hid_t *file_id, void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl); +hid_t bufsize_to_datatype(int dtype); + void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, From 1c0c4bc3218482ffbc20ca10f7ab7b940fe08fd4 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:04:09 +0100 Subject: [PATCH 060/251] Change rdcc_nbytes in H5Pset_chunk_cache to use macros --- src/hdf5_init.c | 3 ++- src/macros.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 5323557..e7ddb63 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -103,7 +103,8 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, unsigned int y = frame_dim[1]; unsigned int x = frame_dim[2]; - if (H5Pset_chunk_cache(dapl, 521, 2 * dtype * y * x, 1.0) < 0) { + if (H5Pset_chunk_cache(dapl, 521, NUM_CHUNKS_IN_CACHE * dtype * y * x, + 1.0) < 0) { fprintf(stderr, "Error in H5Pset)chunk_cache\n"); return; } diff --git a/src/macros.h b/src/macros.h index 81d97ae..ea3399f 100644 --- a/src/macros.h +++ b/src/macros.h @@ -29,4 +29,7 @@ #define MQ1_FIELDS_NUM_FIELDS 19 #define DAC_NUM_FIELDS 28 + +#define NUM_CHUNKSS_IN_CACHE 32 + #endif From e4be56f132aec7fdf99a8743fabe1886d63d55b0 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:07:03 +0100 Subject: [PATCH 061/251] Move bufsize_to_datatype to utils --- src/hdf5_init.c | 29 +---------------------------- src/utils.c | 28 ++++++++++++++++++++++++++++ src/utils.h | 2 ++ 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index e7ddb63..e5d1c9a 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -1,4 +1,5 @@ #include "hdf5_init.h" +#include "utils.h" #include #include #include @@ -42,34 +43,6 @@ void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) } } -hid_t bufsize_to_datatype(int dtype) -{ - hid_t datatype; - switch (dtype) { - case 1: { - datatype = H5T_STD_U8LE; - break; - } - case 2: { - datatype = H5T_STD_U16LE; - break; - } - case 4: { - datatype = H5T_STD_U32LE; - break; - } - case 8: { - datatype = H5T_STD_U64LE; - break; - } - default: { - fprintf(stderr, "Error in datatype, please check input dtype\n"); - return; - } - } - return datatype; -} - void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, diff --git a/src/utils.c b/src/utils.c index 4f8dc02..437df2d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -121,3 +121,31 @@ void header_meta_from_first(FILE *mib_ptr, current_file, __LINE__); } } + +hid_t bufsize_to_datatype(int dtype) +{ + hid_t datatype; + switch (dtype) { + case 1: { + datatype = H5T_STD_U8LE; + break; + } + case 2: { + datatype = H5T_STD_U16LE; + break; + } + case 4: { + datatype = H5T_STD_U32LE; + break; + } + case 8: { + datatype = H5T_STD_U64LE; + break; + } + default: { + fprintf(stderr, "Error in datatype, please check input dtype\n"); + return; + } + } + return datatype; +} diff --git a/src/utils.h b/src/utils.h index 7105499..4f904b8 100644 --- a/src/utils.h +++ b/src/utils.h @@ -15,4 +15,6 @@ void header_meta_from_first(FILE *mib_ptr, unsigned int *det_x, unsigned int *det_y, char *pixel_depth); + +hid_t bufsize_to_datatype(int dtype); #endif From 8024603e78803612be2f32ca2159c5c15c4d4243 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:40:28 +0100 Subject: [PATCH 062/251] Use macros for rdcc_nslot in H5Pset_chunk_cache --- src/hdf5_init.c | 4 ++-- src/macros.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index e5d1c9a..8759538 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -76,8 +76,8 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, unsigned int y = frame_dim[1]; unsigned int x = frame_dim[2]; - if (H5Pset_chunk_cache(dapl, 521, NUM_CHUNKS_IN_CACHE * dtype * y * x, - 1.0) < 0) { + if (H5Pset_chunk_cache(dapl, PRIME_FOR_HASH, + NUM_CHUNKS_IN_CACHE * dtype * y * x, 1.0) < 0) { fprintf(stderr, "Error in H5Pset)chunk_cache\n"); return; } diff --git a/src/macros.h b/src/macros.h index ea3399f..92928b0 100644 --- a/src/macros.h +++ b/src/macros.h @@ -30,6 +30,8 @@ #define DAC_NUM_FIELDS 28 -#define NUM_CHUNKSS_IN_CACHE 32 +#define NUM_CHUNKS_IN_CACHE 32 + +#define PRIME_FOR_HASH 521 #endif From b5d89b02e3c002b94e1785f77e8310bcc134cb13 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:50:09 +0100 Subject: [PATCH 063/251] Add null check to filename --- src/hdf5_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 8759538..f2ae7a7 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -31,6 +31,10 @@ void initialize_plist(hid_t *file_id, void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) { + if (!filename) { + fprintf(stderr, "Empty or other error in filename, please check\n"); + } + if (!H5Iis_valid(fapl) || !H5Iis_valid(fcpl)) { fprintf(stderr, "fapl or fcpl is invalid in initialize_file\n"); return; From 71e3633ca9c738f6de9f5cff8d906f7ba236cf8e Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:56:53 +0100 Subject: [PATCH 064/251] Modify references in create_meta_dataset and create_dac_dataset --- src/hdf5_init_meta.c | 18 +++--------------- src/hdf5_init_meta.h | 8 +++----- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 4754a46..f8a3906 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -7,18 +7,13 @@ #include #include -void create_meta_mq1_fields_dataset(hid_t *file_id, - hid_t *lcpl_id, - hid_t *meta_handle) +void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) { if (meta_handle == NULL) { fprintf(stderr, "meta_handle is NULL in create_meta_fields_dataset\n"); return; } - hid_t file = *file_id; - hid_t lcpl = *lcpl_id; - char meta_group_path[64] = "metadata"; hid_t meta_group = H5Gcreate(file, meta_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); @@ -152,8 +147,8 @@ void create_meta_mq1_fields_dataset(hid_t *file_id, } void create_dac_dataset(unsigned int num_chips, - hid_t *file_id, - hid_t *lcpl_id, + hid_t file, + hid_t lcpl, hid_t *dac_handle) { if (dac_handle == NULL) { @@ -161,13 +156,6 @@ void create_dac_dataset(unsigned int num_chips, return; } - hid_t file = *file_id; - hid_t lcpl; - if (lcpl_id == NULL) { - lcpl = H5P_DEFAULT; - } else { - lcpl = *lcpl_id; - } char chip_group_path[256]; char dataset_path[512]; hid_t chip_group; diff --git a/src/hdf5_init_meta.h b/src/hdf5_init_meta.h index 946f939..132cba0 100644 --- a/src/hdf5_init_meta.h +++ b/src/hdf5_init_meta.h @@ -9,13 +9,11 @@ #include #include -void create_meta_mq1_fields_dataset(hid_t *file_id, - hid_t *lcpl_id, - hid_t *meta_handle); +void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle); void create_dac_dataset(unsigned int num_chips, - hid_t *file_id, - hid_t *lcpl_id, + hid_t file, + hid_t lcpl, hid_t *dac_handle); void close_dataset_handle(hid_t *handle, size_t count); From 9b38dfa9a2568a4b706982e82bda2e834c1280ae Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 15:37:49 +0100 Subject: [PATCH 065/251] Fix reference in initialize_plist --- src/hdf5_init.c | 3 +-- src/hdf5_init.h | 2 +- src/utils.h | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index f2ae7a7..41f78d8 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -3,9 +3,8 @@ #include #include #include -#include -void initialize_plist(hid_t *file_id, +void initialize_plist(char *path, hid_t *fapl_id, hid_t *fcpl_id, hid_t *lcpl_id) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index be57c2b..4408878 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -6,7 +6,7 @@ #include #include -void initialize_plist(hid_t *file_id, +void initialize_plist(char *path, hid_t *fapl_id, hid_t *fcpl_id, hid_t *lcpl_id); diff --git a/src/utils.h b/src/utils.h index 4f904b8..467bf93 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,4 +1,5 @@ // clang-format Language: C +#include #include #ifndef UTILS_H From be1740f0174774d5a14a1e5ca690ec8485d686e4 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 15:45:03 +0100 Subject: [PATCH 066/251] Add logics and macros to determine alignment block size --- src/hdf5_init.c | 5 ++++- src/macros.h | 2 ++ src/utils.c | 12 ++++++++++++ src/utils.h | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 41f78d8..7822413 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -1,4 +1,5 @@ #include "hdf5_init.h" +#include "macros.h" #include "utils.h" #include #include @@ -13,11 +14,13 @@ void initialize_plist(char *path, fprintf(stderr, "Error in creating fcpl in create_file\n"); return; } + unsigned long f_blocksize = get_filesystem_block_size(path); + printf("block size of filesystem: %ld\n", f_blocksize); if ((*fapl_id = H5Pcreate(H5P_FILE_ACCESS)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating fapl in create_file\n"); return; } else { - if (H5Pset_alignment(*fapl_id, 1024, 4096) < 0) { + if (H5Pset_alignment(*fapl_id, ALIGNMENT_THRESHOLD, f_blocksize) < 0) { fprintf(stderr, "Error in H5Pset_alignment\n"); return; } diff --git a/src/macros.h b/src/macros.h index 92928b0..3e67106 100644 --- a/src/macros.h +++ b/src/macros.h @@ -34,4 +34,6 @@ #define PRIME_FOR_HASH 521 +#define ALIGNMENT_THRESHOLD 512 + #endif diff --git a/src/utils.c b/src/utils.c index 437df2d..8ac6a22 100644 --- a/src/utils.c +++ b/src/utils.c @@ -149,3 +149,15 @@ hid_t bufsize_to_datatype(int dtype) } return datatype; } + +unsigned long get_filesystem_block_size(const char *path) +{ + struct statvfs stat; + + if (statvfs(path, &stat) != 0) { + fprintf(stderr, "statvfs failed\n"); + return 1; + } + + return stat.f_bsize; +} diff --git a/src/utils.h b/src/utils.h index 467bf93..288ca59 100644 --- a/src/utils.h +++ b/src/utils.h @@ -18,4 +18,6 @@ void header_meta_from_first(FILE *mib_ptr, char *pixel_depth); hid_t bufsize_to_datatype(int dtype); + +unsigned long get_filesystem_block_size(const char *path); #endif From a135c292549e113dec9687166d8f88ed78a08504 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 15:46:54 +0100 Subject: [PATCH 067/251] Fix typo in initialize_file --- src/hdf5_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 7822413..f5ab288 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -33,7 +33,7 @@ void initialize_plist(char *path, void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) { - if (!filename) { + if (filename == NULL) { fprintf(stderr, "Empty or other error in filename, please check\n"); } From 8c7fbe5f5460a0ba9623a6048ad88b98654792a9 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 16:27:54 +0100 Subject: [PATCH 068/251] Add closing types in create_meta_dataset --- src/hdf5_init_meta.c | 100 ++++++++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 24 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index f8a3906..7986b91 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -30,23 +30,19 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) if (dataspace < 0) { fprintf(stderr, "Error creating dataspace in create_meta_mq1_fields_dataset\n"); + goto label_close1; return; } hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); if (dcpl < 0) { fprintf(stderr, "Error creating dcpl in create_meta_mq1_fields_dataset\n"); - H5Sclose(dataspace); - H5Gclose(meta_group); - return; + goto label_close2; } else { if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { fprintf(stderr, "Error setting chunking in create_meta_mq1_fields_dataset\n"); - H5Pclose(dcpl); - H5Sclose(dataspace); - H5Gclose(meta_group); - return; + goto label_close3; } } @@ -54,10 +50,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) if (dapl < 0) { fprintf(stderr, "Error in creating dapl in create_meta_mq1_fields_dataset\n"); - H5Pclose(dcpl); - H5Sclose(dataspace); - H5Gclose(meta_group); - return; + goto label_close3; } else { } @@ -65,25 +58,73 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) // H5Tset_size(header_id_type, MQ1_CHAR_LEN_HEADER_ID); hid_t pixel_depth_type = H5Tcopy(H5T_C_S1); - H5Tset_size(pixel_depth_type, MQ1_CHAR_LEN_PIXEL_DEPTH); + if (pixel_depth_type < 0) { + fprintf(stderr, "H5Tcopy failed for pixel_depth_type\n"); + goto label_close4; + } + if (H5Tset_size(pixel_depth_type, MQ1_CHAR_LEN_PIXEL_DEPTH) < 0) { + fprintf(stderr, "H5Tsetsize failed for pixel_depth_type\n"); + goto label_close_pixel; + } hid_t sensor_layout_type = H5Tcopy(H5T_C_S1); - H5Tset_size(sensor_layout_type, MQ1_CHAR_LEN_SENSOR_LAYOUT); + if (sensor_layout_type < 0) { + fprintf(stderr, "H5Tcopy failed for sensor_layout_type\n"); + goto label_close_pixel; + } + if (H5Tset_size(sensor_layout_type, MQ1_CHAR_LEN_SENSOR_LAYOUT) < 0) { + fprintf(stderr, "H5Tset_size failed for sensor_layout_type\n"); + goto label_close_sensor; + } hid_t chip_select_type = H5Tcopy(H5T_C_S1); - H5Tset_size(chip_select_type, MQ1_CHAR_LEN_CHIP_SELECT); + if (chip_select_type < 0) { + fprintf(stderr, "H5Tcopy failed for chip_select_type\n"); + goto label_close_sensor; + } + if (H5Tset_size(chip_select_type, MQ1_CHAR_LEN_CHIP_SELECT) < 0) { + fprintf(stderr, "H5Tset_size failed for chip_select_type\n"); + goto label_close_chip; + } hid_t timestamp_type = H5Tcopy(H5T_C_S1); - H5Tset_size(timestamp_type, MQ1_CHAR_LEN_TIMESTAMP); + if (timestamp_type < 0) { + fprintf(stderr, "H5Tcopy failed for timestamp_type\n"); + goto label_close_chip; + } + if (H5Tset_size(timestamp_type, MQ1_CHAR_LEN_TIMESTAMP) < 0) { + fprintf(stderr, "H5Tset_size failed for timestamp_type\n"); + goto label_close_timestamp; + } hid_t header_extension_id_type = H5Tcopy(H5T_C_S1); - H5Tset_size(header_extension_id_type, MQ1_CHAR_LEN_HEADER_EXTENSION_ID); + if (header_extension_id_type < 0) { + fprintf(stderr, "H5Tcopy failed for header_extension_id_type\n"); + goto label_close_timestamp; + } + if (H5Tset_size(header_extension_id_type, MQ1_CHAR_LEN_HEADER_EXTENSION_ID) < + 0) { + fprintf(stderr, "H5Tset_size failed for header_extension_id_type\n"); + goto label_close_header_ext; + } hid_t extended_timestamp_type = H5Tcopy(H5T_C_S1); - H5Tset_size(extended_timestamp_type, MQ1_CHAR_LEN_EXTENDED_TIMESTAMP); + if (extended_timestamp_type < 0) { + fprintf(stderr, "H5Tcopy failed for extended_timestamp_type\n"); + goto label_close_header_ext; + } + if (H5Tset_size(extended_timestamp_type, MQ1_CHAR_LEN_EXTENDED_TIMESTAMP) < + 0) { + fprintf(stderr, "H5Tset_size failed for extended_timestamp_type\n"); + goto label_close_ext_timestamp; + } hsize_t threshold_dims[1] = {MQ1_FLOAT_LEN_THRESHOLD}; hid_t threshold_type = H5Tarray_create(H5T_NATIVE_FLOAT, 1, threshold_dims); + if (threshold_type < 0) { + fprintf(stderr, "H5Tarray_create failed for thresholds\n"); + goto label_close_ext_timestamp; + } struct { const char *name; @@ -132,17 +173,28 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) } // H5Tclose(header_id_type); - H5Tclose(pixel_depth_type); - H5Tclose(sensor_layout_type); - H5Tclose(chip_select_type); - H5Tclose(timestamp_type); - H5Tclose(header_extension_id_type); - H5Tclose(extended_timestamp_type); +label_close_threshold: H5Tclose(threshold_type); +label_close_ext_timestamp: + H5Tclose(extended_timestamp_type); +label_close_header_ext: + H5Tclose(header_extension_id_type); +label_close_timestamp: + H5Tclose(timestamp_type); +label_close_chip: + H5Tclose(chip_select_type); +label_close_sensor: + H5Tclose(sensor_layout_type); +label_close_pixel: + H5Tclose(pixel_depth_type); - H5Pclose(dcpl); +label_close4: H5Pclose(dapl); +label_close3: + H5Pclose(dcpl); +label_close2: H5Sclose(dataspace); +label_close1: H5Gclose(meta_group); } From 94cdec0e80241a63a1ac9b17fdeb64fdc8bc67f5 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 16:41:38 +0100 Subject: [PATCH 069/251] Add logics to check meta_handle in create_meta_dataset --- src/hdf5_init_meta.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 7986b91..2eb7504 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -152,12 +152,17 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) {"bit_depth", H5T_NATIVE_UINT}, }; - size_t num_datasets = sizeof(fields) / sizeof(fields[0]); + size_t num_datasets = sizeof(fields) / sizeof(fields[0]); + size_t num_meta_handle = sizeof(meta_handle) / sizeof(hid_t); + + if (num_meta_handle < num_data) { + fprintf(stderr, "meta_handle not enough space, please check declaration in " + "main and hdf5_init.c"); + goto label_close_ext_timestmp; + } for (size_t i = 0; i < num_datasets; i++) { char dataset_path[256]; - // snprintf(dataset_path, sizeof(dataset_path), "metadata/%s", - // fields[i].name); snprintf(dataset_path, sizeof(dataset_path), "%s", fields[i].name); @@ -187,7 +192,6 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) H5Tclose(sensor_layout_type); label_close_pixel: H5Tclose(pixel_depth_type); - label_close4: H5Pclose(dapl); label_close3: From 60bd787eb95d0de7c4723289b52c31f2b3818a06 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 16:45:50 +0100 Subject: [PATCH 070/251] Fix typo --- src/hdf5_init_meta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 2eb7504..1e9e506 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -158,7 +158,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) if (num_meta_handle < num_data) { fprintf(stderr, "meta_handle not enough space, please check declaration in " "main and hdf5_init.c"); - goto label_close_ext_timestmp; + goto label_close_threshold; } for (size_t i = 0; i < num_datasets; i++) { From 3c97105298cdd26b264e6dfaf4359f1f90024dbe Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 29 Apr 2025 09:29:34 +0100 Subject: [PATCH 071/251] Fix missing return statement --- src/hdf5_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index f5ab288..e1ba14c 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -35,6 +35,7 @@ void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) { if (filename == NULL) { fprintf(stderr, "Empty or other error in filename, please check\n"); + return; } if (!H5Iis_valid(fapl) || !H5Iis_valid(fcpl)) { From 3fd859a203ff67d38d924c3d0a063d92f6f9e7db Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 29 Apr 2025 09:30:41 +0100 Subject: [PATCH 072/251] Remove moved functions declarations in hdf5_init.h --- src/hdf5_init.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 4408878..886132f 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -13,8 +13,6 @@ void initialize_plist(char *path, void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl); -hid_t bufsize_to_datatype(int dtype); - void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, From fdf0c48c6011b86d26aa8458165a9ac4e26f91de Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 29 Apr 2025 10:18:30 +0100 Subject: [PATCH 073/251] Fix typo --- src/hdf5_init_meta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 1e9e506..2e70b64 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -155,7 +155,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) size_t num_datasets = sizeof(fields) / sizeof(fields[0]); size_t num_meta_handle = sizeof(meta_handle) / sizeof(hid_t); - if (num_meta_handle < num_data) { + if (num_meta_handle < num_datasets) { fprintf(stderr, "meta_handle not enough space, please check declaration in " "main and hdf5_init.c"); goto label_close_threshold; From 1df709ca53d818d9653d96e21451f10269ecde05 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 29 Apr 2025 10:37:18 +0100 Subject: [PATCH 074/251] update logi in checking meta_handle and num_dataset --- src/hdf5_init_meta.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 2e70b64..a28f360 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -152,12 +152,11 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) {"bit_depth", H5T_NATIVE_UINT}, }; - size_t num_datasets = sizeof(fields) / sizeof(fields[0]); - size_t num_meta_handle = sizeof(meta_handle) / sizeof(hid_t); + size_t num_datasets = sizeof(fields) / sizeof(fields[0]); - if (num_meta_handle < num_datasets) { - fprintf(stderr, "meta_handle not enough space, please check declaration in " - "main and hdf5_init.c"); + if (num_datasets != MQ1_FIELDS_NUM_FIELD) { + fprintf(stderr, + "Number of dataset not match in create_meta_mq1_fields_dataset\n"); goto label_close_threshold; } From 2f2784e1facb37e592dcfe3c41d2912dbcb76ec1 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 29 Apr 2025 12:54:46 +0100 Subject: [PATCH 075/251] modify logic to check if dataset is valid --- src/hdf5_init_meta.c | 104 +++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index a28f360..7f37577 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -19,7 +19,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) H5Gcreate(file, meta_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); if (meta_group < 0) { fprintf(stderr, "Error creating group in create_meta_mq1_fields_dataset\n"); - return; + goto cleanup; } hsize_t dim[1] = {0}; @@ -30,19 +30,18 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) if (dataspace < 0) { fprintf(stderr, "Error creating dataspace in create_meta_mq1_fields_dataset\n"); - goto label_close1; - return; + goto cleanup; } hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); if (dcpl < 0) { fprintf(stderr, "Error creating dcpl in create_meta_mq1_fields_dataset\n"); - goto label_close2; + goto cleanup; } else { if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { fprintf(stderr, "Error setting chunking in create_meta_mq1_fields_dataset\n"); - goto label_close3; + goto cleanup; } } @@ -50,80 +49,86 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) if (dapl < 0) { fprintf(stderr, "Error in creating dapl in create_meta_mq1_fields_dataset\n"); - goto label_close3; + goto cleanup; } else { } // hid_t header_id_type = H5Tcopy(H5T_C_S1); // H5Tset_size(header_id_type, MQ1_CHAR_LEN_HEADER_ID); - hid_t pixel_depth_type = H5Tcopy(H5T_C_S1); + hid_t pixel_depth_type = H5I_INVALID_HID; + pixel_depth_type = H5Tcopy(H5T_C_S1); if (pixel_depth_type < 0) { fprintf(stderr, "H5Tcopy failed for pixel_depth_type\n"); - goto label_close4; + goto cleanup; } if (H5Tset_size(pixel_depth_type, MQ1_CHAR_LEN_PIXEL_DEPTH) < 0) { fprintf(stderr, "H5Tsetsize failed for pixel_depth_type\n"); - goto label_close_pixel; + goto cleanup; } - hid_t sensor_layout_type = H5Tcopy(H5T_C_S1); + hid_t sensor_layout_type = H5I_INVALID_HID; + sensor_layout_type = H5Tcopy(H5T_C_S1); if (sensor_layout_type < 0) { fprintf(stderr, "H5Tcopy failed for sensor_layout_type\n"); - goto label_close_pixel; + goto cleanup; } if (H5Tset_size(sensor_layout_type, MQ1_CHAR_LEN_SENSOR_LAYOUT) < 0) { fprintf(stderr, "H5Tset_size failed for sensor_layout_type\n"); - goto label_close_sensor; + goto cleanup; } - hid_t chip_select_type = H5Tcopy(H5T_C_S1); + hid_t chip_select_type = H5I_INVALID_HID; + chip_select_type = H5Tcopy(H5T_C_S1); if (chip_select_type < 0) { fprintf(stderr, "H5Tcopy failed for chip_select_type\n"); - goto label_close_sensor; + goto cleanup; } if (H5Tset_size(chip_select_type, MQ1_CHAR_LEN_CHIP_SELECT) < 0) { fprintf(stderr, "H5Tset_size failed for chip_select_type\n"); - goto label_close_chip; + goto cleanup; } - hid_t timestamp_type = H5Tcopy(H5T_C_S1); + hid_t timestamp_type = H5I_INVALID_HID; + timestamp_type = H5Tcopy(H5T_C_S1); if (timestamp_type < 0) { fprintf(stderr, "H5Tcopy failed for timestamp_type\n"); - goto label_close_chip; + goto cleanup; } if (H5Tset_size(timestamp_type, MQ1_CHAR_LEN_TIMESTAMP) < 0) { fprintf(stderr, "H5Tset_size failed for timestamp_type\n"); - goto label_close_timestamp; + goto cleanup; } - hid_t header_extension_id_type = H5Tcopy(H5T_C_S1); + hid_t header_extension_id_type = H5I_INVALID_HID; + header_extension_id_type = H5Tcopy(H5T_C_S1); if (header_extension_id_type < 0) { fprintf(stderr, "H5Tcopy failed for header_extension_id_type\n"); - goto label_close_timestamp; + goto cleanup; } if (H5Tset_size(header_extension_id_type, MQ1_CHAR_LEN_HEADER_EXTENSION_ID) < 0) { fprintf(stderr, "H5Tset_size failed for header_extension_id_type\n"); - goto label_close_header_ext; + goto cleanup; } - hid_t extended_timestamp_type = H5Tcopy(H5T_C_S1); + hid_t extended_timestamp_type = H5I_INVALID_HID; + extended_timestamp_type = H5Tcopy(H5T_C_S1); if (extended_timestamp_type < 0) { fprintf(stderr, "H5Tcopy failed for extended_timestamp_type\n"); - goto label_close_header_ext; + goto cleanup; } if (H5Tset_size(extended_timestamp_type, MQ1_CHAR_LEN_EXTENDED_TIMESTAMP) < 0) { fprintf(stderr, "H5Tset_size failed for extended_timestamp_type\n"); - goto label_close_ext_timestamp; + goto cleanup; } hsize_t threshold_dims[1] = {MQ1_FLOAT_LEN_THRESHOLD}; hid_t threshold_type = H5Tarray_create(H5T_NATIVE_FLOAT, 1, threshold_dims); if (threshold_type < 0) { fprintf(stderr, "H5Tarray_create failed for thresholds\n"); - goto label_close_ext_timestamp; + goto cleanup; } struct { @@ -154,10 +159,10 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) size_t num_datasets = sizeof(fields) / sizeof(fields[0]); - if (num_datasets != MQ1_FIELDS_NUM_FIELD) { + if (num_datasets != MQ1_FIELDS_NUM_FIELDS) { fprintf(stderr, "Number of dataset not match in create_meta_mq1_fields_dataset\n"); - goto label_close_threshold; + goto cleanup; } for (size_t i = 0; i < num_datasets; i++) { @@ -176,29 +181,30 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) meta_handle[i] = dataset; } +cleanup: // H5Tclose(header_id_type); -label_close_threshold: - H5Tclose(threshold_type); -label_close_ext_timestamp: - H5Tclose(extended_timestamp_type); -label_close_header_ext: - H5Tclose(header_extension_id_type); -label_close_timestamp: - H5Tclose(timestamp_type); -label_close_chip: - H5Tclose(chip_select_type); -label_close_sensor: - H5Tclose(sensor_layout_type); -label_close_pixel: - H5Tclose(pixel_depth_type); -label_close4: - H5Pclose(dapl); -label_close3: - H5Pclose(dcpl); -label_close2: - H5Sclose(dataspace); -label_close1: - H5Gclose(meta_group); + if (H5Iis_valid(pixel_depth_type)) + H5Tclose(threshold_type); + if (H5Iis_valid(extended_timestamp_type)) + H5Tclose(extended_timestamp_type); + if (H5Iis_valid(header_extension_id_type)) + H5Tclose(header_extension_id_type); + if (H5Iis_valid(timestamp_type)) + H5Tclose(timestamp_type); + if (H5Iis_valid(chip_select_type)) + H5Tclose(chip_select_type); + if (H5Iis_valid(sensor_layout_type)) + H5Tclose(sensor_layout_type); + if (H5Iis_valid(pixel_depth_type)) + H5Tclose(pixel_depth_type); + if (H5Iis_valid(dapl)) + H5Pclose(dapl); + if (H5Iis_valid(dcpl)) + H5Pclose(dcpl); + if (H5Iis_valid(dataspace)) + H5Sclose(dataspace); + if (H5Iis_valid(meta_group)) + H5Gclose(meta_group); } void create_dac_dataset(unsigned int num_chips, From 1d850971ab0ea5dce1b14d05171a4407315e8a98 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 29 Apr 2025 13:02:46 +0100 Subject: [PATCH 076/251] Change logics in cleaning up hdf5 in create_dac_dataset --- src/hdf5_init_meta.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 7f37577..2ad0aa2 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -233,8 +233,7 @@ void create_dac_dataset(unsigned int num_chips, } else { if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { fprintf(stderr, "Error setting chunking in create_dac_dataset\n"); - H5Pclose(dcpl); - return; + goto cleanup; } } @@ -250,10 +249,7 @@ void create_dac_dataset(unsigned int num_chips, hid_t str_type = H5Tcopy(H5T_C_S1); if (H5Tset_size(str_type, 4) < 0) { fprintf(stderr, "Error setting string type size in create_dac_dataset\n"); - H5Tclose(str_type); - H5Pclose(dcpl); - H5Pclose(dapl); - return; + goto cleanup; } struct { @@ -286,20 +282,13 @@ void create_dac_dataset(unsigned int num_chips, if (chip_group < 0) { fprintf(stderr, "Error creating group chip%02d in create_dac_dataset\n", i); - H5Tclose(str_type); - H5Pclose(dcpl); - H5Pclose(dapl); - return; + goto cleanup; } dataspace = H5Screate_simple(1, dim, max_dim); if (dataspace < 0) { fprintf(stderr, "Error creating dataspace in create_dac_meta_dataset\n"); - H5Tclose(str_type); - H5Pclose(dcpl); - H5Pclose(dapl); - H5Gclose(chip_group); - return; + goto cleanup; } handle_pos = num_datasets * (size_t) i; @@ -329,9 +318,15 @@ void create_dac_dataset(unsigned int num_chips, H5Gclose(chip_group); } - H5Tclose(str_type); - H5Pclose(dcpl); - H5Pclose(dapl); +cleanup: + if (H5Iis_valid(str_type)) + H5Tclose(str_type); + if (H5Iis_valid(dcpl)) + H5Pclose(dcpl); + if (H5Iis_valid(dapl)) + H5Pclose(dapl); + if (H5Iis_valid(chip_group)) + H5Gclose(chip_group); } void close_dataset_handle(hid_t *handle, size_t count) From daa444cc2c1c737750502f963f2a6effe715277e Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 30 Apr 2025 10:01:13 +0100 Subject: [PATCH 077/251] Fix return no value in utils.c --- src/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.c b/src/utils.c index 8ac6a22..e85c214 100644 --- a/src/utils.c +++ b/src/utils.c @@ -144,7 +144,7 @@ hid_t bufsize_to_datatype(int dtype) } default: { fprintf(stderr, "Error in datatype, please check input dtype\n"); - return; + return H5I_INVALID_HID; } } return datatype; From 0fd324f6095bb9653a218cde553ccb948083b672 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 30 Apr 2025 10:02:13 +0100 Subject: [PATCH 078/251] Move include header outside the header guard --- src/hdf5_init.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 886132f..727b3bd 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -1,11 +1,11 @@ // clang-format Language: C -#ifndef HDF5_INIT_H -#define HDF5_INIT_H - #include #include #include +#ifndef HDF5_INIT_H +#define HDF5_INIT_H + void initialize_plist(char *path, hid_t *fapl_id, hid_t *fcpl_id, From 4755992dd274983cefdf70390e3bccaaad356061 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 30 Apr 2025 10:11:35 +0100 Subject: [PATCH 079/251] Add logics to clean up property lists in create_merlin_dataset --- src/hdf5_init.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index e1ba14c..999e7cf 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -64,21 +64,21 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating dcpl\n"); - return; + goto cleanup; } else { if (H5Pset_chunk(dcpl, dim, frame_dim) < 0) { fprintf(stderr, "Error in H5Pset_chunk\n"); - return; + goto cleanup; } if (H5Pset_fill_time(dcpl, H5D_FILL_TIME_NEVER) < 0) { fprintf(stderr, "Error in H5Pset_fill_time\n"); - return; + goto cleanup; } } if ((dapl = H5Pcreate(H5P_DATASET_ACCESS)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating dapl_id\n"); - return; + goto cleanup; } else { unsigned int y = frame_dim[1]; unsigned int x = frame_dim[2]; @@ -86,7 +86,7 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, if (H5Pset_chunk_cache(dapl, PRIME_FOR_HASH, NUM_CHUNKS_IN_CACHE * dtype * y * x, 1.0) < 0) { fprintf(stderr, "Error in H5Pset)chunk_cache\n"); - return; + goto cleanup; } } @@ -96,6 +96,11 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, memspace, lcpl, dcpl, dapl)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating merlin_dataset\n"); - return; + goto cleanup; } +cleanup: + if (H5Iis_valid(dcpl)) + H5Pclose(dcpl); + if (H5Iis_valid(dapl)) + H5Pclose(dapl); } From 617af1bcdf79da222fc6ca9eebd72cc2dc71c331 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 09:28:38 +0100 Subject: [PATCH 080/251] Fix typo on line 88 in hdf5_init.c --- src/hdf5_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 999e7cf..d299e0f 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -85,7 +85,7 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, if (H5Pset_chunk_cache(dapl, PRIME_FOR_HASH, NUM_CHUNKS_IN_CACHE * dtype * y * x, 1.0) < 0) { - fprintf(stderr, "Error in H5Pset)chunk_cache\n"); + fprintf(stderr, "Error in H5Pset_chunk_cache\n"); goto cleanup; } } From 78c9f81f20dd70e1df524e4d785268b11a5415b8 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 09:29:53 +0100 Subject: [PATCH 081/251] Fix typo on line 186 in hdf5_init_meta.c --- src/hdf5_init_meta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 2ad0aa2..81af2b0 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -183,7 +183,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) cleanup: // H5Tclose(header_id_type); - if (H5Iis_valid(pixel_depth_type)) + if (H5Iis_valid(threshold_type)) H5Tclose(threshold_type); if (H5Iis_valid(extended_timestamp_type)) H5Tclose(extended_timestamp_type); From f55c96660e058a358f1d74cb4a7f92c96e5f237f Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 09:32:15 +0100 Subject: [PATCH 082/251] Add header to utils.c --- src/utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils.c b/src/utils.c index e85c214..956080e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,5 +1,6 @@ #include "utils.h" +#include #include #include #include From 00e58660c59b0b52444b743ecaaab0b0aa7ffed3 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 09:37:37 +0100 Subject: [PATCH 083/251] Add null pointer check for path in get_filesystem_block_size --- src/utils.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils.c b/src/utils.c index 956080e..460025d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -154,6 +154,10 @@ hid_t bufsize_to_datatype(int dtype) unsigned long get_filesystem_block_size(const char *path) { struct statvfs stat; + if (!path) { + fprintf(stderr, "Null pointer in get_filesystem_block_size\n"); + return 1; + } if (statvfs(path, &stat) != 0) { fprintf(stderr, "statvfs failed\n"); From 31d704690b7ac7d15e741dfeb4261562387d2a82 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 10:05:34 +0100 Subject: [PATCH 084/251] Move the declaration to the top of function in create_meta)mq1_fields_dataset --- src/hdf5_init_meta.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 81af2b0..298979a 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -9,14 +9,25 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) { + hid_t pixel_depth_type = H5I_INVALID_HID; + hid_t sensor_layout_type = H5I_INVALID_HID; + hid_t chip_select_type = H5I_INVALID_HID; + hid_t timestamp_type = H5I_INVALID_HID; + hid_t header_extension_id_type = H5I_INVALID_HID; + hid_t extended_timestamp_type = H5I_INVALID_HID; + hsize_t threshold_dims[1] = {MQ1_FLOAT_LEN_THRESHOLD}; + hid_t threshold_type = H5I_INVALID_HID; + hid_t dataspace = H5I_INVALID_HID; + hid_t dcpl = H5I_INVALID_HID; + hid_t dapl = H5I_INVALID_HID; + hid_meta_group = H5I_INVALID_HID; if (meta_handle == NULL) { fprintf(stderr, "meta_handle is NULL in create_meta_fields_dataset\n"); return; } char meta_group_path[64] = "metadata"; - hid_t meta_group = - H5Gcreate(file, meta_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); + meta_group = H5Gcreate(file, meta_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); if (meta_group < 0) { fprintf(stderr, "Error creating group in create_meta_mq1_fields_dataset\n"); goto cleanup; @@ -26,14 +37,14 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) hsize_t max_dim[1] = {H5S_UNLIMITED}; hsize_t chunk_dim[1] = {1}; - hid_t dataspace = H5Screate_simple(1, dim, max_dim); + dataspace = H5Screate_simple(1, dim, max_dim); if (dataspace < 0) { fprintf(stderr, "Error creating dataspace in create_meta_mq1_fields_dataset\n"); goto cleanup; } - hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); + dcpl = H5Pcreate(H5P_DATASET_CREATE); if (dcpl < 0) { fprintf(stderr, "Error creating dcpl in create_meta_mq1_fields_dataset\n"); goto cleanup; @@ -45,7 +56,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) } } - hid_t dapl = H5Pcreate(H5P_DATASET_ACCESS); + dapl = H5Pcreate(H5P_DATASET_ACCESS); if (dapl < 0) { fprintf(stderr, "Error in creating dapl in create_meta_mq1_fields_dataset\n"); @@ -56,8 +67,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) // hid_t header_id_type = H5Tcopy(H5T_C_S1); // H5Tset_size(header_id_type, MQ1_CHAR_LEN_HEADER_ID); - hid_t pixel_depth_type = H5I_INVALID_HID; - pixel_depth_type = H5Tcopy(H5T_C_S1); + pixel_depth_type = H5Tcopy(H5T_C_S1); if (pixel_depth_type < 0) { fprintf(stderr, "H5Tcopy failed for pixel_depth_type\n"); goto cleanup; @@ -67,8 +77,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) goto cleanup; } - hid_t sensor_layout_type = H5I_INVALID_HID; - sensor_layout_type = H5Tcopy(H5T_C_S1); + sensor_layout_type = H5Tcopy(H5T_C_S1); if (sensor_layout_type < 0) { fprintf(stderr, "H5Tcopy failed for sensor_layout_type\n"); goto cleanup; @@ -78,8 +87,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) goto cleanup; } - hid_t chip_select_type = H5I_INVALID_HID; - chip_select_type = H5Tcopy(H5T_C_S1); + chip_select_type = H5Tcopy(H5T_C_S1); if (chip_select_type < 0) { fprintf(stderr, "H5Tcopy failed for chip_select_type\n"); goto cleanup; @@ -89,8 +97,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) goto cleanup; } - hid_t timestamp_type = H5I_INVALID_HID; - timestamp_type = H5Tcopy(H5T_C_S1); + timestamp_type = H5Tcopy(H5T_C_S1); if (timestamp_type < 0) { fprintf(stderr, "H5Tcopy failed for timestamp_type\n"); goto cleanup; @@ -100,8 +107,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) goto cleanup; } - hid_t header_extension_id_type = H5I_INVALID_HID; - header_extension_id_type = H5Tcopy(H5T_C_S1); + header_extension_id_type = H5Tcopy(H5T_C_S1); if (header_extension_id_type < 0) { fprintf(stderr, "H5Tcopy failed for header_extension_id_type\n"); goto cleanup; @@ -112,8 +118,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) goto cleanup; } - hid_t extended_timestamp_type = H5I_INVALID_HID; - extended_timestamp_type = H5Tcopy(H5T_C_S1); + extended_timestamp_type = H5Tcopy(H5T_C_S1); if (extended_timestamp_type < 0) { fprintf(stderr, "H5Tcopy failed for extended_timestamp_type\n"); goto cleanup; @@ -124,8 +129,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) goto cleanup; } - hsize_t threshold_dims[1] = {MQ1_FLOAT_LEN_THRESHOLD}; - hid_t threshold_type = H5Tarray_create(H5T_NATIVE_FLOAT, 1, threshold_dims); + threshold_type = H5Tarray_create(H5T_NATIVE_FLOAT, 1, threshold_dims); if (threshold_type < 0) { fprintf(stderr, "H5Tarray_create failed for thresholds\n"); goto cleanup; From dd63a7a99877c001e7547f3cc5340e333d2a4d67 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 10:27:01 +0100 Subject: [PATCH 085/251] Modify declaration in create_merlin_dataset to make it clearer --- src/hdf5_init.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index d299e0f..c49c256 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -59,8 +59,9 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, size_t dim, hsize_t *frame_dim) { - hid_t dcpl; - hid_t dapl; + hid_t dcpl = H5I_INVALID_HID; + hid_t dapl = H5I_INVALID_HID; + hid_t datatype = H5I_INVALID_HID; if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating dcpl\n"); @@ -90,7 +91,7 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, } } - hid_t datatype = bufsize_to_datatype(dtype); + datatype = bufsize_to_datatype(dtype); if ((*merlin_dataset_id = H5Dcreate2(file, merlin_dataset_name, datatype, memspace, lcpl, dcpl, dapl)) == @@ -98,6 +99,7 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, fprintf(stderr, "Error in creating merlin_dataset\n"); goto cleanup; } + cleanup: if (H5Iis_valid(dcpl)) H5Pclose(dcpl); From f453bf33925bc95cba8fafea55cb415870be6260 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 10:27:32 +0100 Subject: [PATCH 086/251] Fix header typo --- src/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.c b/src/utils.c index 460025d..12f1043 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,9 +1,9 @@ #include "utils.h" -#include #include #include #include +#include const char *only_file_name(const char *absolute_file_path) { From 7c276c6504f55342b4f2d384c5533070793e600b Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 10:30:20 +0100 Subject: [PATCH 087/251] Fix typo --- src/hdf5_init_meta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 298979a..3204a4c 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -20,7 +20,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) hid_t dataspace = H5I_INVALID_HID; hid_t dcpl = H5I_INVALID_HID; hid_t dapl = H5I_INVALID_HID; - hid_meta_group = H5I_INVALID_HID; + hid_t meta_group = H5I_INVALID_HID; if (meta_handle == NULL) { fprintf(stderr, "meta_handle is NULL in create_meta_fields_dataset\n"); return; From ff8d5f999f066eca2649c3075d324c6ab14ac498 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 10:36:57 +0100 Subject: [PATCH 088/251] Fix cleanup in create_dac_dataset --- src/hdf5_init_meta.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 3204a4c..81f24c1 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -216,6 +216,13 @@ void create_dac_dataset(unsigned int num_chips, hid_t lcpl, hid_t *dac_handle) { + hid_t dcpl = H5I_INVALID_HID; + hid_t dcpl = H5I_INVALID_HID; + hid_t chip_group = H5I_INVALID_HID; + hid_t dataspace = H5I_INVALID_HID; + hid_t dataset = H5I_INVALID_HID; + hid_t str_type = H5I_INVALID_HID; + if (dac_handle == NULL) { fprintf(stderr, "dac_handle is NULL in create_dac_meta_dataset\n"); return; @@ -223,17 +230,14 @@ void create_dac_dataset(unsigned int num_chips, char chip_group_path[256]; char dataset_path[512]; - hid_t chip_group; hsize_t dim[1] = {0}; hsize_t max_dim[1] = {H5S_UNLIMITED}; hsize_t chunk_dim[1] = {1}; - hid_t dataspace; - hid_t dataset; - hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); + dcpl = H5Pcreate(H5P_DATASET_CREATE); if (dcpl < 0) { fprintf(stderr, "Error creating dcpl in create_dac_dataset\n"); - return; + goto cleanup; } else { if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { fprintf(stderr, "Error setting chunking in create_dac_dataset\n"); @@ -241,16 +245,17 @@ void create_dac_dataset(unsigned int num_chips, } } - hid_t dapl = H5Pcreate(H5P_DATASET_ACCESS); + dapl = H5Pcreate(H5P_DATASET_ACCESS); if (dapl < 0) { fprintf(stderr, "Error creating dapl in create_dac_dataset\n"); - H5Pclose(dcpl); - return; - } else { - // modify dapl if needed + goto cleanup; } - hid_t str_type = H5Tcopy(H5T_C_S1); + str_type = H5Tcopy(H5T_C_S1); + if (str_type < 0) { + fprintf(stderr, "H5Tcopy failed for str_type\n"); + goto cleanup; + } if (H5Tset_size(str_type, 4) < 0) { fprintf(stderr, "Error setting string type size in create_dac_dataset\n"); goto cleanup; @@ -298,8 +303,6 @@ void create_dac_dataset(unsigned int num_chips, handle_pos = num_datasets * (size_t) i; for (size_t j = handle_pos; j < (handle_pos + num_datasets); j++) { - // snprintf(dataset_path, sizeof(dataset_path), "%s/%s", chip_group_path, - // datasets[j-handle_pos].name); snprintf(dataset_path, sizeof(dataset_path), "%s", datasets[j - handle_pos].name); @@ -312,12 +315,8 @@ void create_dac_dataset(unsigned int num_chips, dac_handle[j] = H5I_INVALID_HID; continue; } - // else { - // printf("Created dataset: %s\n", dataset_path); - // } dac_handle[j] = dataset; } - H5Sclose(dataspace); H5Gclose(chip_group); } From 8d7768f5da042f50ddf67b38fee8622a06dbb51f Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 2 May 2025 14:33:03 +0100 Subject: [PATCH 089/251] Remove not needed header in hdf5_init and hdf5_init_meta --- src/hdf5_init.h | 1 - src/hdf5_init_meta.c | 1 - src/hdf5_init_meta.h | 3 --- 3 files changed, 5 deletions(-) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 727b3bd..6038c06 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -1,6 +1,5 @@ // clang-format Language: C #include -#include #include #ifndef HDF5_INIT_H diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 81f24c1..4732827 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -2,7 +2,6 @@ #include "macros.h" #include -#include #include #include #include diff --git a/src/hdf5_init_meta.h b/src/hdf5_init_meta.h index 132cba0..6ea050b 100644 --- a/src/hdf5_init_meta.h +++ b/src/hdf5_init_meta.h @@ -4,10 +4,7 @@ #include "macros.h" #include -#include -#include #include -#include void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle); From 2c02036203e0a37fd49584a457a757c07a1bb913 Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 2 May 2025 14:33:54 +0100 Subject: [PATCH 090/251] Fix typo --- src/hdf5_init_meta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 4732827..4642270 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -216,7 +216,7 @@ void create_dac_dataset(unsigned int num_chips, hid_t *dac_handle) { hid_t dcpl = H5I_INVALID_HID; - hid_t dcpl = H5I_INVALID_HID; + hid_t dapl = H5I_INVALID_HID; hid_t chip_group = H5I_INVALID_HID; hid_t dataspace = H5I_INVALID_HID; hid_t dataset = H5I_INVALID_HID; From b42a56120a5c612f8f4726d86755473ca6bbaa75 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 10:50:21 +0100 Subject: [PATCH 091/251] Remove extra mq1_header allocation in framebuffer.c --- src/framebuffer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index eb760b4..d6253db 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -34,8 +34,7 @@ void allocate_frame_header(framebuffer *fb) fprintf(stderr, "Error in malloc for dac0 in allocate_frame_header\n"); return; } - fb->mq1_header = allocate_MQ1_fields(1); - fb->dac1 = (dac_rx *) malloc(sizeof(dac_rx)); + fb->dac1 = (dac_rx *) malloc(sizeof(dac_rx)); if (!fb->dac1) { fprintf(stderr, "Error in malloc for dac1 in allocate_frame_header\n"); return; From b151ead74dda79bb8eedc154dd2ea0114d3c27b4 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 10:53:54 +0100 Subject: [PATCH 092/251] Fix typo in framebuffer.c --- src/framebuffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index d6253db..0175724 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -65,8 +65,8 @@ void allocate_frame_data(framebuffer *fb) fprintf(stderr, "Error in malloc for fb->rows in allocate_frame_data\n"); return; } - void *data - NULL; - fb->rows = buffer; + void *data = NULL; + fb->rows = buffer; switch (bufsize) { case 1: { data = malloc(sizeof(uint8_t) * detx * dety); @@ -110,8 +110,8 @@ void allocate_frame_data(framebuffer *fb) fprintf(stderr, "malloc failed for data in read_frame"); return; } - fb->data = data for (int i = 0; i < (int) dety; i++) - { + fb->data = data; + for (int i = 0; i < (int) dety; i++) { buffer[i] = (uint64_t *) data + i * detx; } break; @@ -203,7 +203,7 @@ void deallocate_frame(framebuffer *fb) if (fb->dac3) free(fb->dac3); if (fb->mq1_header) { - deallocate_MQ1_fields(fb->mq1_header); + deallocate_MQ1_fields(*(fb->mq1_header)); free(fb->mq1_header); fb->mq1_header = NULL; } From f63bc2238a90c28ac9e7e01a4d53b1c0a5a0dda2 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 11:01:58 +0100 Subject: [PATCH 093/251] Fix bugs due to messing up clang-format, pre-commit and git --- src/framebuffer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index 0175724..0f98bc8 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -15,6 +15,7 @@ #include "framebuffer.h" #include "macros.h" #include "utils.h" +#include #include #include #include @@ -28,8 +29,8 @@ void allocate_frame_header(framebuffer *fb) "Error in malloc for mq1_header in allocate_frame_header\n"); return; } - fb->mq1_header = allocate_MQ1_fields(1); - fb->dac0 = (dac_rx *) malloc(sizeof(dac_rx)); + *(fb->mq1_header) = allocate_MQ1_fields(1); + fb->dac0 = (dac_rx *) malloc(sizeof(dac_rx)); if (!fb->dac0) { fprintf(stderr, "Error in malloc for dac0 in allocate_frame_header\n"); return; @@ -129,7 +130,7 @@ void allocate_frame_data(framebuffer *fb) * The function will return the size of the data after compression * which is from blosc_compress_ctx */ -int compress_frame(framebuffer fb *, +int compress_frame(framebuffer *fb, unsigned int compression_level, unsigned int shuffle, char *compressor, From aef49ce344b78a0756a3d748909207fe5e42ddaa Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 12:00:00 +0100 Subject: [PATCH 094/251] Fix typo in frambuffer --- src/framebuffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index 0f98bc8..f065d36 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -1,4 +1,4 @@ -/* These are the memory allocation functions of he struct framebuffer declared +/* These are functions of the struct framebuffer declared * in framebuffer.h * * allocate_frame_header only allocates mq1_header and dacs in framebuffer @@ -13,8 +13,11 @@ */ #include "framebuffer.h" +#include "io_header.h" #include "macros.h" +#include "mib_header.h" #include "utils.h" + #include #include #include @@ -68,6 +71,7 @@ void allocate_frame_data(framebuffer *fb) } void *data = NULL; fb->rows = buffer; + switch (bufsize) { case 1: { data = malloc(sizeof(uint8_t) * detx * dety); @@ -126,10 +130,6 @@ void allocate_frame_data(framebuffer *fb) } } -/* This is to compress the data inside framebuffer->data - * The function will return the size of the data after compression - * which is from blosc_compress_ctx - */ int compress_frame(framebuffer *fb, unsigned int compression_level, unsigned int shuffle, From 5d97a4ef9e592a92487ad8a1eb44883b487a721e Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 24 Apr 2025 09:36:42 +0100 Subject: [PATCH 095/251] Revert "Add compress_frame" This reverts commit aa303efff4185c4a6074a46c1a2ea7d19190d70a. --- src/framebuffer.c | 57 ----------------------------------------------- 1 file changed, 57 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index f065d36..07173e8 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -8,8 +8,6 @@ * * Please also call deallocate_frame for freeing the memory. deallocate_frame * frees both header and data - * - * compress_frame is used for compressing the data */ #include "framebuffer.h" @@ -130,61 +128,6 @@ void allocate_frame_data(framebuffer *fb) } } -int compress_frame(framebuffer *fb, - unsigned int compression_level, - unsigned int shuffle, - char *compressor, - size_t blocksize, - int numinternalthreads) -{ - int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + - (fb->mq1_header->pixel_depth[2] - '0'); - bufsize = bufsize / 8; - - int detx = (int) *(fb->mq1_header->det_x); - int dety = (int) *(fb->mq1_header->det_y); - - size_t nbytes = dety * detx * bufsize; - size_t destsize = nbytes + BLOSC_MAX_OVERHEAD; - void *dest = malloc(destsize); - if (!dest) { - fprintf(stderr, "Error in malloc for dest\n"); - return -1; - } - - int cbytes = blosc_compress_ctx(compression_level, shuffle, bufsize, nbytes, - fb->data, dest, destsize, compressor, - blocksize, numinternalthreads); - if (cbytes < 0) { - fprintf(stderr, "Error in blosc_compress\n"); - free(dest); - return -1; - } - if (cbytes == 0) { - fprintf(stderr, "Blosc returned 0 bytes (uncompressible?). Forcing " - "fallback to uncompressed write.\n"); - cbytes = nbytes; - return cbytes; - } - // for showing compression ratio in each frame, profiling purposes - // if (cbytes != 0) { - // printf("compression: %ld -> %d (%.1fx)\n", nbytes, cbytes, (1. * nbytes) / - // cbytes); - //} - - free(fb->data); - fb->data = malloc(destsize); - if (!fb->data) { - fprintf(stderr, "Error in malloc for fb->data\n"); - free(dest); - return -1; - } - - memcpy(fb->data, dest, cbytes); - free(dest); - return cbytes; -} - void deallocate_frame(framebuffer *fb) { if (fb == NULL) { From 6061f70c008afd554b3875413815ed1c04d3e984 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 24 Apr 2025 09:38:20 +0100 Subject: [PATCH 096/251] Revert "Add compress_frame in framebuffer.h" This reverts commit 76ecde8008fbc65e0a85b4b3025a98b97be585a5. --- src/framebuffer.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/framebuffer.h b/src/framebuffer.h index 50574b3..084fe24 100644 --- a/src/framebuffer.h +++ b/src/framebuffer.h @@ -23,14 +23,6 @@ void allocate_frame_header(framebuffer *fb); // allocate memory for data in framebuffer void allocate_frame_data(framebuffer *fb); -// compress data inside framebuffer -int compress_frame(framebuffer *fb, - unsigned int compression_level, - unsigned int shuffle, - char *compressor, - size_t blocksize, - int numinternalthreads); - // this is responsible for freeing the whole struct void deallocate_frame(framebuffer *fb); From 2252de9a47870b49bf693b2112cb1f317457bb18 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 24 Apr 2025 09:39:21 +0100 Subject: [PATCH 097/251] Remove bin --- bin/main.out | Bin 112520 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 bin/main.out diff --git a/bin/main.out b/bin/main.out deleted file mode 100755 index b9751d80d27177c00dd388a9ef68ee7231653441..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112520 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 Date: Thu, 24 Apr 2025 09:44:40 +0100 Subject: [PATCH 098/251] Remove blosc.h --- src/framebuffer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index 07173e8..1d8f1a2 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -16,7 +16,6 @@ #include "mib_header.h" #include "utils.h" -#include #include #include #include From 52474628984ce0631d768c6d5508a858196d6b2e Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 24 Apr 2025 09:48:24 +0100 Subject: [PATCH 099/251] Remove include drectory in config.mk --- config.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config.mk b/config.mk index 89b0dee..c04ba0c 100644 --- a/config.mk +++ b/config.mk @@ -1,7 +1,6 @@ # === Directories === SRCDIR := src OBJDIR := obj -INCDIR := include HDFDIR ?= $(HDF5_ROOT) BUILD ?= debug @@ -24,7 +23,7 @@ else $(error Unknown BUILD type: $(BUILD)) endif -CFLAGS += -I$(SRCDIR) -I$(INCDIR) -I$(HDFDIR)/include +CFLAGS += -I$(SRCDIR) -I$(HDFDIR)/include LDFLAGS += -L$(HDFDIR)/lib -lhdf5 # === Sources === From 5ab62694576900d8175a58523eb5b7e669fa1955 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 23 Apr 2025 13:04:48 +0100 Subject: [PATCH 100/251] Change checking in close_handle --- src/hdf5_init_meta.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 016a925..4754a46 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -270,6 +270,9 @@ void create_dac_dataset(unsigned int num_chips, dac_handle[j] = H5I_INVALID_HID; continue; } + // else { + // printf("Created dataset: %s\n", dataset_path); + // } dac_handle[j] = dataset; } @@ -284,10 +287,12 @@ void create_dac_dataset(unsigned int num_chips, void close_dataset_handle(hid_t *handle, size_t count) { - if (!handle) + if (!handle) { + printf("No handle\n"); return; + } for (size_t i = 0; i < count; i++) { - if (handle[i] >= 0) { + if (H5Iis_valid(handle[i])) { H5Dclose(handle[i]); } } From 9b19711206801196dfc4f16e2284168ef598ccb5 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Fri, 25 Apr 2025 11:49:12 +0100 Subject: [PATCH 101/251] Remove extra comment in hdf5_init --- src/hdf5_init.c | 16 ---------------- src/hdf5_init.h | 2 -- 2 files changed, 18 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 0194f01..bab9711 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -1,6 +1,5 @@ #include "hdf5_init.h" #include "blosc_filter.h" - #include #include #include @@ -8,21 +7,6 @@ #include #include -/* -// functions for debugging -void check_space_and_storage(hid_t dset) { - H5D_space_status_t space_status; - hsize_t storage_size; - - status = H5Dget_space_status(dset, &space_status); - storage_size = H5Dget_storage_size(dset); - printf("Space for dataset has%sbeen allocated. \n", space_status == -H5D_SPACE_STATUS_ALLOCATED ? " " : " NOT "); printf("Storage size for dataset is -: %ld bytes.\n", (long)storage_size); -} -*/ - -// REAL functions void initialize_file_and_plist(char *filename, hid_t *file_id, hid_t *fapl_id, diff --git a/src/hdf5_init.h b/src/hdf5_init.h index f365b39..91093ce 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -8,8 +8,6 @@ #include #include -// void check_space_and_storage(hid_t dset); - void initialize_file_and_plist(char *filename, hid_t *file_id, hid_t *fapl_id, From 421fd48b47d490496039ee03276904cb4f2db6fa Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 14:25:03 +0100 Subject: [PATCH 102/251] Refactored initialize plist and file --- src/hdf5_init.c | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index bab9711..c2821a0 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -7,14 +7,12 @@ #include #include -void initialize_file_and_plist(char *filename, - hid_t *file_id, - hid_t *fapl_id, - hid_t *fcpl_id) +void initialize_plist(char *filename, + hid_t *file_id, + hid_t *fapl_id, + hid_t *fcpl_id, + hid_t *lcpl_id) { - unsigned mode = H5F_ACC_TRUNC; - char *version, *date; - if ((*fcpl_id = H5Pcreate(H5P_FILE_CREATE)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating fcpl in create_file\n"); return; @@ -34,34 +32,26 @@ void initialize_file_and_plist(char *filename, "file already existed\n"); return; } - if (register_blosc(&version, &date) < 0) { - fprintf(stderr, "Error in register_blosc\n"); + if ((*lcpl_id = H5Pcreate(H5P_LINK_CREATE)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating lcpl in initialize_dataset_plist\n"); return; - } else { - printf("Blosc version info: %s (%s)\n", version, date); - free(version); - free(date); } } -void initialize_lcpl(hid_t *lcpl_id) +void initialize_file(char *filename, + hid_t *file_id, + hid_t fapl, + hid_t fcpl) { - if ((*lcpl_id = H5Pcreate(H5P_LINK_CREATE)) == H5I_INVALID_HID) { - fprintf(stderr, "Error in creating lcpl in initialize_dataset_plist\n"); + if (!H5Iis_valid(fapl) || !H5Iis_valid(fcpl)) { + fprintf(stderr, "fapl or fcpl is invalid in initialize_file\n"); return; } - /* - else { - if (H5Pset_create_intermediate_group(*lcpl_id, 1) < 0) { - fprintf(stderr, "Error in H5Pset_create_intermediate_group\n"); - return; - } - if (H5Pset_char_encoding(*lcpl_id, H5T_CSET_UTF8) < 0) { - fprintf(stderr, "Error in H5Pset_char_encoding\n"); - return; - } + + if ((*file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating file_id in intialize_file\n"); + return; } - */ } void create_merlin_dataset(hid_t *merlin_dataset_id, From 96c9ed43f290f5a32c15391433796d919e928987 Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 14:31:26 +0100 Subject: [PATCH 103/251] Remove commented out code --- src/hdf5_init.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index c2821a0..199d1d2 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -70,7 +70,6 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t lcpl = *lcpl_id; hid_t dcpl; hid_t dapl; - // int fill_value = -1; unsigned int cd_values[7] = {0}; if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { @@ -85,12 +84,6 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, fprintf(stderr, "Error in H5Pset_fill_time\n"); return; } - /* - if (H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fill_value) < 0) { - fprintf(stderr, "Error in H5Pset_fill_value\n"); - return; - } - */ cd_values[0] = 0; cd_values[1] = compression_level; cd_values[2] = shuffle; From 8b1f61e36d30c0ecbcd4d72e9cac796e5b47bc8d Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 14:46:55 +0100 Subject: [PATCH 104/251] Fix clang-format --- src/hdf5_init.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 199d1d2..86b71cf 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -38,17 +38,15 @@ void initialize_plist(char *filename, } } -void initialize_file(char *filename, - hid_t *file_id, - hid_t fapl, - hid_t fcpl) +void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) { if (!H5Iis_valid(fapl) || !H5Iis_valid(fcpl)) { fprintf(stderr, "fapl or fcpl is invalid in initialize_file\n"); return; } - if ((*file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) == H5I_INVALID_HID) { + if ((*file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl)) == + H5I_INVALID_HID) { fprintf(stderr, "Error in creating file_id in intialize_file\n"); return; } From 73e221bc2a0eee3d723bcfa40312fca298c4e47f Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 18:31:17 +0100 Subject: [PATCH 105/251] Remove blosc related code --- src/hdf5_init.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 86b71cf..4e88180 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -2,7 +2,6 @@ #include "blosc_filter.h" #include #include -#include #include #include #include @@ -26,12 +25,6 @@ void initialize_plist(char *filename, return; } } - if ((*file_id = H5Fcreate(filename, mode, *fcpl_id, *fapl_id)) == - H5I_INVALID_HID) { - fprintf(stderr, "Error in creating file_id in create_file, please check if " - "file already existed\n"); - return; - } if ((*lcpl_id = H5Pcreate(H5P_LINK_CREATE)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating lcpl in initialize_dataset_plist\n"); return; @@ -82,18 +75,6 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, fprintf(stderr, "Error in H5Pset_fill_time\n"); return; } - cd_values[0] = 0; - cd_values[1] = compression_level; - cd_values[2] = shuffle; - cd_values[3] = 0; // blocksize - cd_values[4] = 0; // unused - cd_values[5] = 0; // unused - cd_values[6] = compressor; - if (H5Pset_filter(dcpl, FILTER_BLOSC, H5Z_FLAG_OPTIONAL, 7, cd_values) < - 0) { - fprintf(stderr, "Error in H5Pset_filter\n"); - return; - } } if ((dapl = H5Pcreate(H5P_DATASET_ACCESS)) == H5I_INVALID_HID) { From fa6219aa892e897038feebe4c35fda834dcd762e Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Fri, 25 Apr 2025 18:44:34 +0100 Subject: [PATCH 106/251] Remove more blosc code --- src/hdf5_init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 4e88180..f67544d 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -1,6 +1,4 @@ #include "hdf5_init.h" -#include "blosc_filter.h" -#include #include #include #include @@ -61,7 +59,6 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t lcpl = *lcpl_id; hid_t dcpl; hid_t dapl; - unsigned int cd_values[7] = {0}; if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating dcpl\n"); From dd3b7fab58d884aa6755e8e13a3d9f196c8f00ae Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 10:35:29 +0100 Subject: [PATCH 107/251] Changes to references in initialize_plist and initialize_file --- src/hdf5_init.c | 3 +-- src/hdf5_init.h | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index f67544d..efd53ad 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -4,8 +4,7 @@ #include #include -void initialize_plist(char *filename, - hid_t *file_id, +void initialize_plist(hid_t *file_id, hid_t *fapl_id, hid_t *fcpl_id, hid_t *lcpl_id) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 91093ce..22f858e 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -8,12 +8,12 @@ #include #include -void initialize_file_and_plist(char *filename, - hid_t *file_id, - hid_t *fapl_id, - hid_t *fcpl_id); +void initialize_plist(hid_t *file_id, + hid_t *fapl_id, + hid_t *fcpl_id, + hid_t *lcpl_id); -void initialize_lcpl(hid_t *lcpl_id); +void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl); void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t *file_id, From 7aa5528d0ca2fa51ef3816247238d0a335efb18a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 11:02:33 +0100 Subject: [PATCH 108/251] Modifying references in create_merlin_dataset --- src/hdf5_init.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index efd53ad..3318682 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -43,19 +43,14 @@ void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) } void create_merlin_dataset(hid_t *merlin_dataset_id, - hid_t *file_id, + hid_t file, char *merlin_dataset_name, int dtype, hid_t memspace, - hid_t *lcpl_id, + hid_t lcpl, size_t dim, - hsize_t *frame_dim, - unsigned int compression_level, - unsigned int shuffle, - unsigned int compressor) + hsize_t *frame_dim) { - hid_t file = *file_id; - hid_t lcpl = *lcpl_id; hid_t dcpl; hid_t dapl; From 940faced88e65c7932817654597a2bd052ba0a95 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 11:03:28 +0100 Subject: [PATCH 109/251] Modifying references in header file for create_merlin_dataset --- src/hdf5_init.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 22f858e..5df4bc3 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -16,15 +16,12 @@ void initialize_plist(hid_t *file_id, void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl); void create_merlin_dataset(hid_t *merlin_dataset_id, - hid_t *file_id, + hid_t file, char *merlin_dataset_name, int dtype, hid_t memspace, - hid_t *lcpl_id, + hid_t lcpl, size_t dim, - hsize_t *frame_dim, - unsigned int compression_level, - unsigned int shuffle, - unsigned int compressor); + hsize_t *frame_dim); #endif From 0276243e937584e2a4bedb529f27faa6f984cb7b Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 11:11:27 +0100 Subject: [PATCH 110/251] Create function bufsize_to_datatype to handle logic related to different data size --- src/hdf5_init.c | 52 +++++++++++++++++++++++++++---------------------- src/hdf5_init.h | 4 ++-- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 3318682..5323557 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -42,6 +42,34 @@ void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) } } +hid_t bufsize_to_datatype(int dtype) +{ + hid_t datatype; + switch (dtype) { + case 1: { + datatype = H5T_STD_U8LE; + break; + } + case 2: { + datatype = H5T_STD_U16LE; + break; + } + case 4: { + datatype = H5T_STD_U32LE; + break; + } + case 8: { + datatype = H5T_STD_U64LE; + break; + } + default: { + fprintf(stderr, "Error in datatype, please check input dtype\n"); + return; + } + } + return datatype; +} + void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, @@ -81,29 +109,7 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, } } - hid_t datatype; - switch (dtype) { - case 1: { - datatype = H5T_STD_U8LE; - break; - } - case 2: { - datatype = H5T_STD_U16LE; - break; - } - case 4: { - datatype = H5T_STD_U32LE; - break; - } - case 8: { - datatype = H5T_STD_U64LE; - break; - } - default: { - fprintf(stderr, "Error in datatype, please check input dtype\n"); - return; - } - } + hid_t datatype = bufsize_to_datatype(dtype); if ((*merlin_dataset_id = H5Dcreate2(file, merlin_dataset_name, datatype, memspace, lcpl, dcpl, dapl)) == diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 5df4bc3..be57c2b 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -3,10 +3,8 @@ #define HDF5_INIT_H #include -#include #include #include -#include void initialize_plist(hid_t *file_id, hid_t *fapl_id, @@ -15,6 +13,8 @@ void initialize_plist(hid_t *file_id, void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl); +hid_t bufsize_to_datatype(int dtype); + void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, From 57fffd5b3950bc3c39e1ccdc097fc7f6be2f06b0 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:04:09 +0100 Subject: [PATCH 111/251] Change rdcc_nbytes in H5Pset_chunk_cache to use macros --- src/hdf5_init.c | 3 ++- src/macros.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 5323557..e7ddb63 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -103,7 +103,8 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, unsigned int y = frame_dim[1]; unsigned int x = frame_dim[2]; - if (H5Pset_chunk_cache(dapl, 521, 2 * dtype * y * x, 1.0) < 0) { + if (H5Pset_chunk_cache(dapl, 521, NUM_CHUNKS_IN_CACHE * dtype * y * x, + 1.0) < 0) { fprintf(stderr, "Error in H5Pset)chunk_cache\n"); return; } diff --git a/src/macros.h b/src/macros.h index 81d97ae..ea3399f 100644 --- a/src/macros.h +++ b/src/macros.h @@ -29,4 +29,7 @@ #define MQ1_FIELDS_NUM_FIELDS 19 #define DAC_NUM_FIELDS 28 + +#define NUM_CHUNKSS_IN_CACHE 32 + #endif From c4b4236a8f0fa52ef8aac91e6b887dd8a02c8dff Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:07:03 +0100 Subject: [PATCH 112/251] Move bufsize_to_datatype to utils --- src/hdf5_init.c | 29 +---------------------------- src/utils.c | 28 ++++++++++++++++++++++++++++ src/utils.h | 2 ++ 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index e7ddb63..e5d1c9a 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -1,4 +1,5 @@ #include "hdf5_init.h" +#include "utils.h" #include #include #include @@ -42,34 +43,6 @@ void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) } } -hid_t bufsize_to_datatype(int dtype) -{ - hid_t datatype; - switch (dtype) { - case 1: { - datatype = H5T_STD_U8LE; - break; - } - case 2: { - datatype = H5T_STD_U16LE; - break; - } - case 4: { - datatype = H5T_STD_U32LE; - break; - } - case 8: { - datatype = H5T_STD_U64LE; - break; - } - default: { - fprintf(stderr, "Error in datatype, please check input dtype\n"); - return; - } - } - return datatype; -} - void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, diff --git a/src/utils.c b/src/utils.c index 4f8dc02..437df2d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -121,3 +121,31 @@ void header_meta_from_first(FILE *mib_ptr, current_file, __LINE__); } } + +hid_t bufsize_to_datatype(int dtype) +{ + hid_t datatype; + switch (dtype) { + case 1: { + datatype = H5T_STD_U8LE; + break; + } + case 2: { + datatype = H5T_STD_U16LE; + break; + } + case 4: { + datatype = H5T_STD_U32LE; + break; + } + case 8: { + datatype = H5T_STD_U64LE; + break; + } + default: { + fprintf(stderr, "Error in datatype, please check input dtype\n"); + return; + } + } + return datatype; +} diff --git a/src/utils.h b/src/utils.h index 7105499..4f904b8 100644 --- a/src/utils.h +++ b/src/utils.h @@ -15,4 +15,6 @@ void header_meta_from_first(FILE *mib_ptr, unsigned int *det_x, unsigned int *det_y, char *pixel_depth); + +hid_t bufsize_to_datatype(int dtype); #endif From 1548b4687feadcf9f9023b0e083585d6f020743e Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:40:28 +0100 Subject: [PATCH 113/251] Use macros for rdcc_nslot in H5Pset_chunk_cache --- src/hdf5_init.c | 4 ++-- src/macros.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index e5d1c9a..8759538 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -76,8 +76,8 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, unsigned int y = frame_dim[1]; unsigned int x = frame_dim[2]; - if (H5Pset_chunk_cache(dapl, 521, NUM_CHUNKS_IN_CACHE * dtype * y * x, - 1.0) < 0) { + if (H5Pset_chunk_cache(dapl, PRIME_FOR_HASH, + NUM_CHUNKS_IN_CACHE * dtype * y * x, 1.0) < 0) { fprintf(stderr, "Error in H5Pset)chunk_cache\n"); return; } diff --git a/src/macros.h b/src/macros.h index ea3399f..92928b0 100644 --- a/src/macros.h +++ b/src/macros.h @@ -30,6 +30,8 @@ #define DAC_NUM_FIELDS 28 -#define NUM_CHUNKSS_IN_CACHE 32 +#define NUM_CHUNKS_IN_CACHE 32 + +#define PRIME_FOR_HASH 521 #endif From 0cf9a82344f77b3b3d773ace60c0cb1f9c8d0cf4 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:50:09 +0100 Subject: [PATCH 114/251] Add null check to filename --- src/hdf5_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index 8759538..f2ae7a7 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -31,6 +31,10 @@ void initialize_plist(hid_t *file_id, void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) { + if (!filename) { + fprintf(stderr, "Empty or other error in filename, please check\n"); + } + if (!H5Iis_valid(fapl) || !H5Iis_valid(fcpl)) { fprintf(stderr, "fapl or fcpl is invalid in initialize_file\n"); return; From 6c9eae9eb2b7324a06ba2865305591ddb6cf27a0 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 28 Apr 2025 13:56:53 +0100 Subject: [PATCH 115/251] Modify references in create_meta_dataset and create_dac_dataset --- src/hdf5_init_meta.c | 18 +++--------------- src/hdf5_init_meta.h | 8 +++----- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 4754a46..f8a3906 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -7,18 +7,13 @@ #include #include -void create_meta_mq1_fields_dataset(hid_t *file_id, - hid_t *lcpl_id, - hid_t *meta_handle) +void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) { if (meta_handle == NULL) { fprintf(stderr, "meta_handle is NULL in create_meta_fields_dataset\n"); return; } - hid_t file = *file_id; - hid_t lcpl = *lcpl_id; - char meta_group_path[64] = "metadata"; hid_t meta_group = H5Gcreate(file, meta_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); @@ -152,8 +147,8 @@ void create_meta_mq1_fields_dataset(hid_t *file_id, } void create_dac_dataset(unsigned int num_chips, - hid_t *file_id, - hid_t *lcpl_id, + hid_t file, + hid_t lcpl, hid_t *dac_handle) { if (dac_handle == NULL) { @@ -161,13 +156,6 @@ void create_dac_dataset(unsigned int num_chips, return; } - hid_t file = *file_id; - hid_t lcpl; - if (lcpl_id == NULL) { - lcpl = H5P_DEFAULT; - } else { - lcpl = *lcpl_id; - } char chip_group_path[256]; char dataset_path[512]; hid_t chip_group; diff --git a/src/hdf5_init_meta.h b/src/hdf5_init_meta.h index 946f939..132cba0 100644 --- a/src/hdf5_init_meta.h +++ b/src/hdf5_init_meta.h @@ -9,13 +9,11 @@ #include #include -void create_meta_mq1_fields_dataset(hid_t *file_id, - hid_t *lcpl_id, - hid_t *meta_handle); +void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle); void create_dac_dataset(unsigned int num_chips, - hid_t *file_id, - hid_t *lcpl_id, + hid_t file, + hid_t lcpl, hid_t *dac_handle); void close_dataset_handle(hid_t *handle, size_t count); From 893a584c04124caa6aee4ae6d71a0634b7c6e14c Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 6 May 2025 09:39:29 +0100 Subject: [PATCH 116/251] resolve conflicts --- src/hdf5_init.c | 38 +++++--- src/hdf5_init.h | 11 +-- src/hdf5_init_meta.c | 222 +++++++++++++++++++++++++++---------------- src/hdf5_init_meta.h | 3 - 4 files changed, 168 insertions(+), 106 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index f2ae7a7..c49c256 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -1,11 +1,11 @@ #include "hdf5_init.h" +#include "macros.h" #include "utils.h" #include #include #include -#include -void initialize_plist(hid_t *file_id, +void initialize_plist(char *path, hid_t *fapl_id, hid_t *fcpl_id, hid_t *lcpl_id) @@ -14,11 +14,13 @@ void initialize_plist(hid_t *file_id, fprintf(stderr, "Error in creating fcpl in create_file\n"); return; } + unsigned long f_blocksize = get_filesystem_block_size(path); + printf("block size of filesystem: %ld\n", f_blocksize); if ((*fapl_id = H5Pcreate(H5P_FILE_ACCESS)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating fapl in create_file\n"); return; } else { - if (H5Pset_alignment(*fapl_id, 1024, 4096) < 0) { + if (H5Pset_alignment(*fapl_id, ALIGNMENT_THRESHOLD, f_blocksize) < 0) { fprintf(stderr, "Error in H5Pset_alignment\n"); return; } @@ -31,8 +33,9 @@ void initialize_plist(hid_t *file_id, void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) { - if (!filename) { + if (filename == NULL) { fprintf(stderr, "Empty or other error in filename, please check\n"); + return; } if (!H5Iis_valid(fapl) || !H5Iis_valid(fcpl)) { @@ -56,43 +59,50 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, size_t dim, hsize_t *frame_dim) { - hid_t dcpl; - hid_t dapl; + hid_t dcpl = H5I_INVALID_HID; + hid_t dapl = H5I_INVALID_HID; + hid_t datatype = H5I_INVALID_HID; if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating dcpl\n"); - return; + goto cleanup; } else { if (H5Pset_chunk(dcpl, dim, frame_dim) < 0) { fprintf(stderr, "Error in H5Pset_chunk\n"); - return; + goto cleanup; } if (H5Pset_fill_time(dcpl, H5D_FILL_TIME_NEVER) < 0) { fprintf(stderr, "Error in H5Pset_fill_time\n"); - return; + goto cleanup; } } if ((dapl = H5Pcreate(H5P_DATASET_ACCESS)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating dapl_id\n"); - return; + goto cleanup; } else { unsigned int y = frame_dim[1]; unsigned int x = frame_dim[2]; if (H5Pset_chunk_cache(dapl, PRIME_FOR_HASH, NUM_CHUNKS_IN_CACHE * dtype * y * x, 1.0) < 0) { - fprintf(stderr, "Error in H5Pset)chunk_cache\n"); - return; + fprintf(stderr, "Error in H5Pset_chunk_cache\n"); + goto cleanup; } } - hid_t datatype = bufsize_to_datatype(dtype); + datatype = bufsize_to_datatype(dtype); if ((*merlin_dataset_id = H5Dcreate2(file, merlin_dataset_name, datatype, memspace, lcpl, dcpl, dapl)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating merlin_dataset\n"); - return; + goto cleanup; } + +cleanup: + if (H5Iis_valid(dcpl)) + H5Pclose(dcpl); + if (H5Iis_valid(dapl)) + H5Pclose(dapl); } diff --git a/src/hdf5_init.h b/src/hdf5_init.h index be57c2b..6038c06 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -1,20 +1,17 @@ // clang-format Language: C -#ifndef HDF5_INIT_H -#define HDF5_INIT_H - #include -#include #include -void initialize_plist(hid_t *file_id, +#ifndef HDF5_INIT_H +#define HDF5_INIT_H + +void initialize_plist(char *path, hid_t *fapl_id, hid_t *fcpl_id, hid_t *lcpl_id); void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl); -hid_t bufsize_to_datatype(int dtype); - void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index f8a3906..4642270 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -2,88 +2,137 @@ #include "macros.h" #include -#include #include #include #include void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) { + hid_t pixel_depth_type = H5I_INVALID_HID; + hid_t sensor_layout_type = H5I_INVALID_HID; + hid_t chip_select_type = H5I_INVALID_HID; + hid_t timestamp_type = H5I_INVALID_HID; + hid_t header_extension_id_type = H5I_INVALID_HID; + hid_t extended_timestamp_type = H5I_INVALID_HID; + hsize_t threshold_dims[1] = {MQ1_FLOAT_LEN_THRESHOLD}; + hid_t threshold_type = H5I_INVALID_HID; + hid_t dataspace = H5I_INVALID_HID; + hid_t dcpl = H5I_INVALID_HID; + hid_t dapl = H5I_INVALID_HID; + hid_t meta_group = H5I_INVALID_HID; if (meta_handle == NULL) { fprintf(stderr, "meta_handle is NULL in create_meta_fields_dataset\n"); return; } char meta_group_path[64] = "metadata"; - hid_t meta_group = - H5Gcreate(file, meta_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); + meta_group = H5Gcreate(file, meta_group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); if (meta_group < 0) { fprintf(stderr, "Error creating group in create_meta_mq1_fields_dataset\n"); - return; + goto cleanup; } hsize_t dim[1] = {0}; hsize_t max_dim[1] = {H5S_UNLIMITED}; hsize_t chunk_dim[1] = {1}; - hid_t dataspace = H5Screate_simple(1, dim, max_dim); + dataspace = H5Screate_simple(1, dim, max_dim); if (dataspace < 0) { fprintf(stderr, "Error creating dataspace in create_meta_mq1_fields_dataset\n"); - return; + goto cleanup; } - hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); + dcpl = H5Pcreate(H5P_DATASET_CREATE); if (dcpl < 0) { fprintf(stderr, "Error creating dcpl in create_meta_mq1_fields_dataset\n"); - H5Sclose(dataspace); - H5Gclose(meta_group); - return; + goto cleanup; } else { if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { fprintf(stderr, "Error setting chunking in create_meta_mq1_fields_dataset\n"); - H5Pclose(dcpl); - H5Sclose(dataspace); - H5Gclose(meta_group); - return; + goto cleanup; } } - hid_t dapl = H5Pcreate(H5P_DATASET_ACCESS); + dapl = H5Pcreate(H5P_DATASET_ACCESS); if (dapl < 0) { fprintf(stderr, "Error in creating dapl in create_meta_mq1_fields_dataset\n"); - H5Pclose(dcpl); - H5Sclose(dataspace); - H5Gclose(meta_group); - return; + goto cleanup; } else { } // hid_t header_id_type = H5Tcopy(H5T_C_S1); // H5Tset_size(header_id_type, MQ1_CHAR_LEN_HEADER_ID); - hid_t pixel_depth_type = H5Tcopy(H5T_C_S1); - H5Tset_size(pixel_depth_type, MQ1_CHAR_LEN_PIXEL_DEPTH); + pixel_depth_type = H5Tcopy(H5T_C_S1); + if (pixel_depth_type < 0) { + fprintf(stderr, "H5Tcopy failed for pixel_depth_type\n"); + goto cleanup; + } + if (H5Tset_size(pixel_depth_type, MQ1_CHAR_LEN_PIXEL_DEPTH) < 0) { + fprintf(stderr, "H5Tsetsize failed for pixel_depth_type\n"); + goto cleanup; + } - hid_t sensor_layout_type = H5Tcopy(H5T_C_S1); - H5Tset_size(sensor_layout_type, MQ1_CHAR_LEN_SENSOR_LAYOUT); + sensor_layout_type = H5Tcopy(H5T_C_S1); + if (sensor_layout_type < 0) { + fprintf(stderr, "H5Tcopy failed for sensor_layout_type\n"); + goto cleanup; + } + if (H5Tset_size(sensor_layout_type, MQ1_CHAR_LEN_SENSOR_LAYOUT) < 0) { + fprintf(stderr, "H5Tset_size failed for sensor_layout_type\n"); + goto cleanup; + } - hid_t chip_select_type = H5Tcopy(H5T_C_S1); - H5Tset_size(chip_select_type, MQ1_CHAR_LEN_CHIP_SELECT); + chip_select_type = H5Tcopy(H5T_C_S1); + if (chip_select_type < 0) { + fprintf(stderr, "H5Tcopy failed for chip_select_type\n"); + goto cleanup; + } + if (H5Tset_size(chip_select_type, MQ1_CHAR_LEN_CHIP_SELECT) < 0) { + fprintf(stderr, "H5Tset_size failed for chip_select_type\n"); + goto cleanup; + } - hid_t timestamp_type = H5Tcopy(H5T_C_S1); - H5Tset_size(timestamp_type, MQ1_CHAR_LEN_TIMESTAMP); + timestamp_type = H5Tcopy(H5T_C_S1); + if (timestamp_type < 0) { + fprintf(stderr, "H5Tcopy failed for timestamp_type\n"); + goto cleanup; + } + if (H5Tset_size(timestamp_type, MQ1_CHAR_LEN_TIMESTAMP) < 0) { + fprintf(stderr, "H5Tset_size failed for timestamp_type\n"); + goto cleanup; + } - hid_t header_extension_id_type = H5Tcopy(H5T_C_S1); - H5Tset_size(header_extension_id_type, MQ1_CHAR_LEN_HEADER_EXTENSION_ID); + header_extension_id_type = H5Tcopy(H5T_C_S1); + if (header_extension_id_type < 0) { + fprintf(stderr, "H5Tcopy failed for header_extension_id_type\n"); + goto cleanup; + } + if (H5Tset_size(header_extension_id_type, MQ1_CHAR_LEN_HEADER_EXTENSION_ID) < + 0) { + fprintf(stderr, "H5Tset_size failed for header_extension_id_type\n"); + goto cleanup; + } - hid_t extended_timestamp_type = H5Tcopy(H5T_C_S1); - H5Tset_size(extended_timestamp_type, MQ1_CHAR_LEN_EXTENDED_TIMESTAMP); + extended_timestamp_type = H5Tcopy(H5T_C_S1); + if (extended_timestamp_type < 0) { + fprintf(stderr, "H5Tcopy failed for extended_timestamp_type\n"); + goto cleanup; + } + if (H5Tset_size(extended_timestamp_type, MQ1_CHAR_LEN_EXTENDED_TIMESTAMP) < + 0) { + fprintf(stderr, "H5Tset_size failed for extended_timestamp_type\n"); + goto cleanup; + } - hsize_t threshold_dims[1] = {MQ1_FLOAT_LEN_THRESHOLD}; - hid_t threshold_type = H5Tarray_create(H5T_NATIVE_FLOAT, 1, threshold_dims); + threshold_type = H5Tarray_create(H5T_NATIVE_FLOAT, 1, threshold_dims); + if (threshold_type < 0) { + fprintf(stderr, "H5Tarray_create failed for thresholds\n"); + goto cleanup; + } struct { const char *name; @@ -113,10 +162,14 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) size_t num_datasets = sizeof(fields) / sizeof(fields[0]); + if (num_datasets != MQ1_FIELDS_NUM_FIELDS) { + fprintf(stderr, + "Number of dataset not match in create_meta_mq1_fields_dataset\n"); + goto cleanup; + } + for (size_t i = 0; i < num_datasets; i++) { char dataset_path[256]; - // snprintf(dataset_path, sizeof(dataset_path), "metadata/%s", - // fields[i].name); snprintf(dataset_path, sizeof(dataset_path), "%s", fields[i].name); @@ -131,19 +184,30 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) meta_handle[i] = dataset; } +cleanup: // H5Tclose(header_id_type); - H5Tclose(pixel_depth_type); - H5Tclose(sensor_layout_type); - H5Tclose(chip_select_type); - H5Tclose(timestamp_type); - H5Tclose(header_extension_id_type); - H5Tclose(extended_timestamp_type); - H5Tclose(threshold_type); - - H5Pclose(dcpl); - H5Pclose(dapl); - H5Sclose(dataspace); - H5Gclose(meta_group); + if (H5Iis_valid(threshold_type)) + H5Tclose(threshold_type); + if (H5Iis_valid(extended_timestamp_type)) + H5Tclose(extended_timestamp_type); + if (H5Iis_valid(header_extension_id_type)) + H5Tclose(header_extension_id_type); + if (H5Iis_valid(timestamp_type)) + H5Tclose(timestamp_type); + if (H5Iis_valid(chip_select_type)) + H5Tclose(chip_select_type); + if (H5Iis_valid(sensor_layout_type)) + H5Tclose(sensor_layout_type); + if (H5Iis_valid(pixel_depth_type)) + H5Tclose(pixel_depth_type); + if (H5Iis_valid(dapl)) + H5Pclose(dapl); + if (H5Iis_valid(dcpl)) + H5Pclose(dcpl); + if (H5Iis_valid(dataspace)) + H5Sclose(dataspace); + if (H5Iis_valid(meta_group)) + H5Gclose(meta_group); } void create_dac_dataset(unsigned int num_chips, @@ -151,6 +215,13 @@ void create_dac_dataset(unsigned int num_chips, hid_t lcpl, hid_t *dac_handle) { + hid_t dcpl = H5I_INVALID_HID; + hid_t dapl = H5I_INVALID_HID; + hid_t chip_group = H5I_INVALID_HID; + hid_t dataspace = H5I_INVALID_HID; + hid_t dataset = H5I_INVALID_HID; + hid_t str_type = H5I_INVALID_HID; + if (dac_handle == NULL) { fprintf(stderr, "dac_handle is NULL in create_dac_meta_dataset\n"); return; @@ -158,41 +229,35 @@ void create_dac_dataset(unsigned int num_chips, char chip_group_path[256]; char dataset_path[512]; - hid_t chip_group; hsize_t dim[1] = {0}; hsize_t max_dim[1] = {H5S_UNLIMITED}; hsize_t chunk_dim[1] = {1}; - hid_t dataspace; - hid_t dataset; - hid_t dcpl = H5Pcreate(H5P_DATASET_CREATE); + dcpl = H5Pcreate(H5P_DATASET_CREATE); if (dcpl < 0) { fprintf(stderr, "Error creating dcpl in create_dac_dataset\n"); - return; + goto cleanup; } else { if (H5Pset_chunk(dcpl, 1, chunk_dim) < 0) { fprintf(stderr, "Error setting chunking in create_dac_dataset\n"); - H5Pclose(dcpl); - return; + goto cleanup; } } - hid_t dapl = H5Pcreate(H5P_DATASET_ACCESS); + dapl = H5Pcreate(H5P_DATASET_ACCESS); if (dapl < 0) { fprintf(stderr, "Error creating dapl in create_dac_dataset\n"); - H5Pclose(dcpl); - return; - } else { - // modify dapl if needed + goto cleanup; } - hid_t str_type = H5Tcopy(H5T_C_S1); + str_type = H5Tcopy(H5T_C_S1); + if (str_type < 0) { + fprintf(stderr, "H5Tcopy failed for str_type\n"); + goto cleanup; + } if (H5Tset_size(str_type, 4) < 0) { fprintf(stderr, "Error setting string type size in create_dac_dataset\n"); - H5Tclose(str_type); - H5Pclose(dcpl); - H5Pclose(dapl); - return; + goto cleanup; } struct { @@ -225,27 +290,18 @@ void create_dac_dataset(unsigned int num_chips, if (chip_group < 0) { fprintf(stderr, "Error creating group chip%02d in create_dac_dataset\n", i); - H5Tclose(str_type); - H5Pclose(dcpl); - H5Pclose(dapl); - return; + goto cleanup; } dataspace = H5Screate_simple(1, dim, max_dim); if (dataspace < 0) { fprintf(stderr, "Error creating dataspace in create_dac_meta_dataset\n"); - H5Tclose(str_type); - H5Pclose(dcpl); - H5Pclose(dapl); - H5Gclose(chip_group); - return; + goto cleanup; } handle_pos = num_datasets * (size_t) i; for (size_t j = handle_pos; j < (handle_pos + num_datasets); j++) { - // snprintf(dataset_path, sizeof(dataset_path), "%s/%s", chip_group_path, - // datasets[j-handle_pos].name); snprintf(dataset_path, sizeof(dataset_path), "%s", datasets[j - handle_pos].name); @@ -258,19 +314,21 @@ void create_dac_dataset(unsigned int num_chips, dac_handle[j] = H5I_INVALID_HID; continue; } - // else { - // printf("Created dataset: %s\n", dataset_path); - // } dac_handle[j] = dataset; } - H5Sclose(dataspace); H5Gclose(chip_group); } - H5Tclose(str_type); - H5Pclose(dcpl); - H5Pclose(dapl); +cleanup: + if (H5Iis_valid(str_type)) + H5Tclose(str_type); + if (H5Iis_valid(dcpl)) + H5Pclose(dcpl); + if (H5Iis_valid(dapl)) + H5Pclose(dapl); + if (H5Iis_valid(chip_group)) + H5Gclose(chip_group); } void close_dataset_handle(hid_t *handle, size_t count) diff --git a/src/hdf5_init_meta.h b/src/hdf5_init_meta.h index 132cba0..6ea050b 100644 --- a/src/hdf5_init_meta.h +++ b/src/hdf5_init_meta.h @@ -4,10 +4,7 @@ #include "macros.h" #include -#include -#include #include -#include void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle); From 00aae9ab1edd59b1c0f89a2952eb01f45931582e Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 6 May 2025 09:43:42 +0100 Subject: [PATCH 117/251] Update path in clang-format-check.yml --- .github/workflows/clang-format-check.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 026acb7..dbac87b 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -15,7 +15,6 @@ jobs: matrix: path: - 'src' - - 'include' steps: - uses: actions/checkout@v4 - name: Run clang-format style check From 2f063ff2d16beb67be671abe5a61c42496179af3 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 6 May 2025 09:46:22 +0100 Subject: [PATCH 118/251] resolve conflicts --- src/utils.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils.c b/src/utils.c index 117ba21..12f1043 100644 --- a/src/utils.c +++ b/src/utils.c @@ -146,7 +146,6 @@ hid_t bufsize_to_datatype(int dtype) default: { fprintf(stderr, "Error in datatype, please check input dtype\n"); return H5I_INVALID_HID; - } } return datatype; @@ -167,4 +166,3 @@ unsigned long get_filesystem_block_size(const char *path) return stat.f_bsize; } - From e95577ecfaffe882745b2b4d7e0b957e4232dcf9 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 6 May 2025 14:23:49 +0100 Subject: [PATCH 119/251] add codes for header_id in metadata --- src/hdf5_init_meta.c | 19 ++++++++++++---- src/io_header.c | 54 ++++++++++++++++++++++++++++---------------- src/io_header.h | 1 + src/macros.h | 2 +- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 4642270..33aaa40 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -8,6 +8,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) { + hid_t header_id_type = H5I_INVALID_HID; hid_t pixel_depth_type = H5I_INVALID_HID; hid_t sensor_layout_type = H5I_INVALID_HID; hid_t chip_select_type = H5I_INVALID_HID; @@ -63,8 +64,15 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) } else { } - // hid_t header_id_type = H5Tcopy(H5T_C_S1); - // H5Tset_size(header_id_type, MQ1_CHAR_LEN_HEADER_ID); + header_id_type = H5Tcopy(H5T_C_S1); + if (header_id_type < 0) { + fprintf(stderr, "H5Tcopt failed for header_id_type\n"); + goto cleanup; + } + if (H5Tset_size(header_id_type, MQ1_CHAR_LEN_HEADER_ID) < 0) { + fprintf(stderr, "H5Tset_size failed for header_id_type\n"); + goto cleanup; + } pixel_depth_type = H5Tcopy(H5T_C_S1); if (pixel_depth_type < 0) { @@ -72,7 +80,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) goto cleanup; } if (H5Tset_size(pixel_depth_type, MQ1_CHAR_LEN_PIXEL_DEPTH) < 0) { - fprintf(stderr, "H5Tsetsize failed for pixel_depth_type\n"); + fprintf(stderr, "H5Tset_size failed for pixel_depth_type\n"); goto cleanup; } @@ -138,7 +146,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) const char *name; hid_t type; } fields[] = { - //{"header_id", header_id_type}, + {"header_id", header_id_type}, {"max_length", H5T_NATIVE_UINT}, {"sequence_number", H5T_NATIVE_UINT}, {"header_bytes", H5T_NATIVE_UINT}, @@ -185,7 +193,8 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) } cleanup: - // H5Tclose(header_id_type); + if (H5Iis_valid(header_id_type)) + H5Tclose(header_id_type); if (H5Iis_valid(threshold_type)) H5Tclose(threshold_type); if (H5Iis_valid(extended_timestamp_type)) diff --git a/src/io_header.c b/src/io_header.c index 766f61d..0e7c146 100644 --- a/src/io_header.c +++ b/src/io_header.c @@ -113,6 +113,13 @@ MQ1_fields allocate_MQ1_fields(unsigned int nheaders) mq1_fields.max_length = nheaders; + mq1_fields.header_id = (char *) malloc(sizeof(char) * MQ1_CHAR_LEN_HEADER_ID * + mq1_fields.max_length); + if (mq1_fields.header_id == NULL) { + perror("Memory allocation error for header id"); + exit(1); + } + mq1_fields.sequence_number = (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); if (mq1_fields.sequence_number == NULL) { @@ -252,6 +259,8 @@ MQ1_fields allocate_MQ1_fields(unsigned int nheaders) /* ensure all allocated memory is free */ void deallocate_MQ1_fields(MQ1_fields mq1_fields) { + free(mq1_fields.header_id); + mq1_fields.header_id = NULL; free(mq1_fields.sequence_number); mq1_fields.sequence_number = NULL; free(mq1_fields.header_bytes); @@ -309,6 +318,9 @@ void fill_MQ1_single_fields(MQ1_fields *mq1_field, mq1_field->num_chips[index] = mq1_h.num_chips; mq1_field->det_x[index] = mq1_h.det_x; mq1_field->det_y[index] = mq1_h.det_y; + /*header_id is char[4]*/ + snprintf(mq1_field->header_id + index * MQ1_CHAR_LEN_HEADER_ID, + MQ1_CHAR_LEN_HEADER_ID, "%s", mq1_h.header_id); /*pixel_depth is char[4]*/ snprintf(mq1_field->pixel_depth + index * MQ1_CHAR_LEN_PIXEL_DEPTH, MQ1_CHAR_LEN_PIXEL_DEPTH, "%s", mq1_h.pixel_depth); @@ -359,6 +371,9 @@ void fill_MQ1_quad_fields(MQ1_fields *mq1_field, unsigned int index, mq1q mq1_h) mq1_field->num_chips[index] = mq1_h.num_chips; mq1_field->det_x[index] = mq1_h.det_x; mq1_field->det_y[index] = mq1_h.det_y; + /*header_id is char[4]*/ + snprintf(mq1_field->header_id + index * MQ1_CHAR_LEN_HEADER_ID, + MQ1_CHAR_LEN_HEADER_ID, "%s", mq1_h.header_id); /*pixel_depth is char[4]*/ snprintf(mq1_field->pixel_depth + index * MQ1_CHAR_LEN_PIXEL_DEPTH, MQ1_CHAR_LEN_PIXEL_DEPTH, "%s", mq1_h.pixel_depth); @@ -405,26 +420,27 @@ info *mq1_fields_info(MQ1_fields *fields_struct) if (!fields) return NULL; - fields[0] = (info) {"max_length", &fields_struct->max_length}; - fields[1] = (info) {"sequence_number", fields_struct->sequence_number}; - fields[2] = (info) {"header_bytes", fields_struct->header_bytes}; - fields[3] = (info) {"num_chips", fields_struct->num_chips}; - fields[4] = (info) {"det_x", fields_struct->det_x}; - fields[5] = (info) {"det_y", fields_struct->det_y}; - fields[6] = (info) {"pixel_depth", fields_struct->pixel_depth}; - fields[7] = (info) {"sensor_layout", fields_struct->sensor_layout}; - fields[8] = (info) {"chip_select", fields_struct->chip_select}; - fields[9] = (info) {"timestamp", fields_struct->timestamp}; - fields[10] = (info) {"exposure_time_s", fields_struct->exposure_time_s}; - fields[11] = (info) {"counter", fields_struct->counter}; - fields[12] = (info) {"colour_mode", fields_struct->colour_mode}; - fields[13] = (info) {"gain_mode", fields_struct->gain_mode}; - fields[14] = (info) {"threshold", fields_struct->threshold}; - fields[15] = + fields[0] = (info) {"header_id", fields_struct->header_id}; + fields[1] = (info) {"max_length", &fields_struct->max_length}; + fields[2] = (info) {"sequence_number", fields_struct->sequence_number}; + fields[3] = (info) {"header_bytes", fields_struct->header_bytes}; + fields[4] = (info) {"num_chips", fields_struct->num_chips}; + fields[5] = (info) {"det_x", fields_struct->det_x}; + fields[6] = (info) {"det_y", fields_struct->det_y}; + fields[7] = (info) {"pixel_depth", fields_struct->pixel_depth}; + fields[8] = (info) {"sensor_layout", fields_struct->sensor_layout}; + fields[9] = (info) {"chip_select", fields_struct->chip_select}; + fields[10] = (info) {"timestamp", fields_struct->timestamp}; + fields[11] = (info) {"exposure_time_s", fields_struct->exposure_time_s}; + fields[12] = (info) {"counter", fields_struct->counter}; + fields[13] = (info) {"colour_mode", fields_struct->colour_mode}; + fields[14] = (info) {"gain_mode", fields_struct->gain_mode}; + fields[15] = (info) {"threshold", fields_struct->threshold}; + fields[16] = (info) {"header_extension_id", fields_struct->header_extension_id}; - fields[16] = (info) {"extended_timestamp", fields_struct->extended_timestamp}; - fields[17] = (info) {"exposure_time_ns", fields_struct->exposure_time_ns}; - fields[18] = (info) {"bit_depth", fields_struct->bit_depth}; + fields[17] = (info) {"extended_timestamp", fields_struct->extended_timestamp}; + fields[18] = (info) {"exposure_time_ns", fields_struct->exposure_time_ns}; + fields[19] = (info) {"bit_depth", fields_struct->bit_depth}; return fields; } diff --git a/src/io_header.h b/src/io_header.h index da02e0f..753455b 100644 --- a/src/io_header.h +++ b/src/io_header.h @@ -9,6 +9,7 @@ #define IO_HEADER_H typedef struct { + char *header_id; unsigned int max_length; unsigned int *sequence_number; unsigned int *header_bytes; diff --git a/src/macros.h b/src/macros.h index 3e67106..7126648 100644 --- a/src/macros.h +++ b/src/macros.h @@ -26,7 +26,7 @@ #define MQ1_CHAR_LEN_EXTENDED_TIMESTAMP 31 -#define MQ1_FIELDS_NUM_FIELDS 19 +#define MQ1_FIELDS_NUM_FIELDS 20 #define DAC_NUM_FIELDS 28 From 86adb76cdee9d79f2395a09827ab6f141eaa35c7 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 09:57:48 +0100 Subject: [PATCH 120/251] Remove --- src/read.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/read.c b/src/read.c index bb76b72..3c3fd0e 100644 --- a/src/read.c +++ b/src/read.c @@ -5,7 +5,6 @@ #include "parser.h" #include "utils.h" -#include #include #include #include From 4035eecfd05bf5a1134a85815a03eb344c8e92b4 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 10:27:53 +0100 Subject: [PATCH 121/251] Change to use local macros for header size --- src/read.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/read.c b/src/read.c index 3c3fd0e..6b6edb5 100644 --- a/src/read.c +++ b/src/read.c @@ -10,17 +10,26 @@ #include #include +#define HEADER_LOC_IN_BUF 16 +#define HEADERSIZE 6 + void read_header(FILE *mib_ptr, long offset, framebuffer *fb) { fseek(mib_ptr, offset, SEEK_SET); - char buf[16] = {0}; - char headersize_str[6] = {0}; - fread(buf, sizeof(char), 16, mib_ptr); - memcpy(headersize_str, buf + 11, 5); - headersize_str[5] = '\0'; - int headersize = atoi(headersize_str); - char *header = malloc(sizeof(char) * headersize); - MQ1_fields *mq1_header = malloc(sizeof(MQ1_fields)); + + char buf[HEADER_LOC_IN_BUF] = {0}; + char headersize_str[HEADERSIZE] = {0}; + size_t status = fread(buf, sizeof(char), HEADER_LOC_IN_BUF, mib_ptr); + if (status != HEADER_LOC_IN_BF) { + fprintf(stderr, "fread error in read_header\n"); + return; + } + memcpy(headersize_str, buf + HEADER_LOC_IN_BUF - HEADERSIZE + 1, + HEADERSIZE - 1); + headersize_str[HEADERSIZE - 1] = '\0'; + int headersize = strtol(headersize_str); + char *header = malloc(sizeof(char) * headersize); + MQ1_fields *mq1_header = malloc(sizeof(MQ1_fields)); if (!mq1_header) { fprintf(stderr, "malloc fail for mq1_header in read_header\n"); free(header); From 1189faaad27ea46c1e8bc99373c9b3bf4a41f691 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 10:29:15 +0100 Subject: [PATCH 122/251] Add checks for fseek and fread --- src/read.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/read.c b/src/read.c index 6b6edb5..d8a8861 100644 --- a/src/read.c +++ b/src/read.c @@ -15,7 +15,18 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) { - fseek(mib_ptr, offset, SEEK_SET); + if (mib_ptr == NULL || fb == NULL) { + fprintf(stderr, "Missing input mib_ptr or fb in read_header\n"); + return; + } + if (offset < 0) { + fprintf(stderr, "offset is negative, please check input\n"); + return; + } + if (fseek(mib_ptr, offset, SEEK_SET) != 0) { + fprintf(stderr, "fseek error in read_header\n"); + return; + } char buf[HEADER_LOC_IN_BUF] = {0}; char headersize_str[HEADERSIZE] = {0}; @@ -38,8 +49,16 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) } *mq1_header = allocate_MQ1_fields(1); - fseek(mib_ptr, offset, SEEK_SET); - fread(header, sizeof(char), headersize, mib_ptr); + if (fseek(mib_ptr, offset, SEEK_SET) != 0) { + fprintf(stderr, "fseek error in read_header\n"); + return; + } + + status = fread(header, sizeof(char), headersize, mib_ptr); + if (status != headersize) { + fprintf(stderr, "fread error in read_header\n"); + return; + } switch (headersize) { case 384: { @@ -98,18 +117,22 @@ void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) int detx = (int) *(fb->mq1_header->det_x); int dety = (int) *(fb->mq1_header->det_y); - // move mib_ptr to the correct place - fseek(mib_ptr, offset + headersize, SEEK_SET); + if (fseek(mib_ptr, offset + headersize, SEEK_SET) != 0) { + fprintf(stderr, "fseek error in read_frame\n"); + return; + } - // write data into buffer uint8_t *raw_data = malloc(bufsize * detx * dety); if (!raw_data) { fprintf(stderr, "malloc failed for raw_data in read_frame\n"); return; } - // TO-DO: add checks for corruption - fread(raw_data, sizeof(char), bufsize * detx * dety, mib_ptr); + size_t status = fread(raw_data, sizeof(char), bufsize * detx * dety, mib_ptr); + if (status != bufsize * detx * dety) { + fprintf(stderr, "fread error in read_frame\n"); + return; + } for (int i = 0; i < dety; i++) { for (int j = 0; j < detx; j++) { From 5ad7a630ebb4058ed3f1a2a2f61d53500453180c Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 10:29:38 +0100 Subject: [PATCH 123/251] Add checks for dac pointer --- src/read.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/read.c b/src/read.c index d8a8861..dadc372 100644 --- a/src/read.c +++ b/src/read.c @@ -64,6 +64,10 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) case 384: { mq1s mq1_single; parse_mq1_single(header, &mq1_single); + if (fb->dac0 == NULL) { + fprintf(stderr, "NULL dac pointer in read_header\n"); + return; + } memcpy(fb->dac0, &mq1_single.dac0, sizeof(dac_rx)); fb->dac1 = NULL; fb->dac2 = NULL; @@ -75,6 +79,11 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) case 768: { mq1q mq1_quad; parse_mq1_quad(header, &mq1_quad); + if (fb->dac0 == NULL || fb->dac1 == NULL || fb->dac2 == NULL || + fb->dac3 == NULL) { + fprintf(stderr, "NULL dac pointer in read_header\n"); + return; + } memcpy(fb->dac0, &mq1_quad.dac0, sizeof(dac_rx)); memcpy(fb->dac1, &mq1_quad.dac1, sizeof(dac_rx)); memcpy(fb->dac2, &mq1_quad.dac2, sizeof(dac_rx)); From e0b74a18bc6038db8d120ca8d36ba07e30424f64 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 10:30:13 +0100 Subject: [PATCH 124/251] add checks for mq1_header pointers --- src/read.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/read.c b/src/read.c index dadc372..31c6944 100644 --- a/src/read.c +++ b/src/read.c @@ -117,6 +117,17 @@ void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) return; } + if (fb->mq1_header == NULL) { + fprintf(stderr, "NULL pointer fb->mq1_header in read_frame\n"); + return; + } else { + if (fb->mq1_header->header_bytes == NULL || fb->mq1_header->det_x == NULL || + fb->mq1_header->det_y == NULL) { + fprintf(stderr, "NULL pointer inside fb->mq1_header in read_frame\n"); + return; + } + } + int headersize = *(fb->mq1_header->header_bytes); int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + From ec43f5f7a55b4ec65c5daf9ff4e38b35fd8aa84a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 10:30:31 +0100 Subject: [PATCH 125/251] Add checks for bufsize size range --- src/read.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/read.c b/src/read.c index 31c6944..a2b4bb8 100644 --- a/src/read.c +++ b/src/read.c @@ -133,6 +133,10 @@ void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + (fb->mq1_header->pixel_depth[2] - '0'); bufsize = bufsize / 8; + if (bufsize != 1 || bufsize != 2 || bufsize != 4 || bufsize != 8) { + fprintf(stderr, "not supported bufsize in read_frame\n"); + return; + } int detx = (int) *(fb->mq1_header->det_x); int dety = (int) *(fb->mq1_header->det_y); @@ -186,6 +190,10 @@ void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) ((uint64_t **) fb->rows)[i][j] = value; break; } + default: { + fprintf(stderr, "not supported bufsize\n"); + return; + } } } } From d4c43d0f3487f1b84831ec3fbf2d229bbeecf527 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 10:32:15 +0100 Subject: [PATCH 126/251] Use macros for header bytes size --- src/read.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/read.c b/src/read.c index a2b4bb8..a489582 100644 --- a/src/read.c +++ b/src/read.c @@ -61,7 +61,7 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) } switch (headersize) { - case 384: { + case MQ1_SINGLE_HEADER_BYTES: { mq1s mq1_single; parse_mq1_single(header, &mq1_single); if (fb->dac0 == NULL) { @@ -76,7 +76,7 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) fb->mq1_header = mq1_header; break; } - case 768: { + case MQ1_QUAD_HEADER_BYTES: { mq1q mq1_quad; parse_mq1_quad(header, &mq1_quad); if (fb->dac0 == NULL || fb->dac1 == NULL || fb->dac2 == NULL || From 73c1016078dafea6e127d060541eadc6817ced0b Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 10:42:26 +0100 Subject: [PATCH 127/251] Fix logic error --- src/read.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/read.c b/src/read.c index a489582..95463b6 100644 --- a/src/read.c +++ b/src/read.c @@ -133,7 +133,7 @@ void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + (fb->mq1_header->pixel_depth[2] - '0'); bufsize = bufsize / 8; - if (bufsize != 1 || bufsize != 2 || bufsize != 4 || bufsize != 8) { + if (bufsize != 1 && bufsize != 2 && bufsize != 4 && bufsize != 8) { fprintf(stderr, "not supported bufsize in read_frame\n"); return; } From 31f7cb2b460d82a30da0fba614c070100a59fc9a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 14:12:32 +0100 Subject: [PATCH 128/251] Fix memory leak in read.c --- src/read.c | 62 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/src/read.c b/src/read.c index 95463b6..b2f807e 100644 --- a/src/read.c +++ b/src/read.c @@ -17,47 +17,59 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) { if (mib_ptr == NULL || fb == NULL) { fprintf(stderr, "Missing input mib_ptr or fb in read_header\n"); - return; + goto cleanup; } if (offset < 0) { fprintf(stderr, "offset is negative, please check input\n"); - return; + goto cleanup; } if (fseek(mib_ptr, offset, SEEK_SET) != 0) { fprintf(stderr, "fseek error in read_header\n"); - return; + goto cleanup; } char buf[HEADER_LOC_IN_BUF] = {0}; char headersize_str[HEADERSIZE] = {0}; size_t status = fread(buf, sizeof(char), HEADER_LOC_IN_BUF, mib_ptr); - if (status != HEADER_LOC_IN_BF) { + if (status != HEADER_LOC_IN_BUF) { fprintf(stderr, "fread error in read_header\n"); - return; + goto cleanup; } memcpy(headersize_str, buf + HEADER_LOC_IN_BUF - HEADERSIZE + 1, HEADERSIZE - 1); headersize_str[HEADERSIZE - 1] = '\0'; - int headersize = strtol(headersize_str); - char *header = malloc(sizeof(char) * headersize); - MQ1_fields *mq1_header = malloc(sizeof(MQ1_fields)); + char *end_ptr; + long unsigned int headersize = strtol(headersize_str, &end_ptr, 10); + if (end_ptr == headersize_str) { + fprintf(stderr, "headersize strtol error in read_header, no digit found\n"); + goto cleanup; + } else if (*end_ptr != '\0') { + fprintf(stderr, + "headersize strtol error in read_header, invalid character: %c\n", + *end_ptr); + goto cleanup; + } + char *header = malloc(sizeof(char) * headersize); + if (!header) { + fprintf(stderr, "malloc fail for header in read_header\n"); + goto cleanup; + } + MQ1_fields *mq1_header = malloc(sizeof(MQ1_fields)); if (!mq1_header) { fprintf(stderr, "malloc fail for mq1_header in read_header\n"); - free(header); - header = NULL; - return; + goto cleanup; } *mq1_header = allocate_MQ1_fields(1); if (fseek(mib_ptr, offset, SEEK_SET) != 0) { fprintf(stderr, "fseek error in read_header\n"); - return; + goto cleanup; } status = fread(header, sizeof(char), headersize, mib_ptr); if (status != headersize) { fprintf(stderr, "fread error in read_header\n"); - return; + goto cleanup; } switch (headersize) { @@ -66,7 +78,7 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) parse_mq1_single(header, &mq1_single); if (fb->dac0 == NULL) { fprintf(stderr, "NULL dac pointer in read_header\n"); - return; + goto cleanup; } memcpy(fb->dac0, &mq1_single.dac0, sizeof(dac_rx)); fb->dac1 = NULL; @@ -82,7 +94,7 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) if (fb->dac0 == NULL || fb->dac1 == NULL || fb->dac2 == NULL || fb->dac3 == NULL) { fprintf(stderr, "NULL dac pointer in read_header\n"); - return; + goto cleanup; } memcpy(fb->dac0, &mq1_quad.dac0, sizeof(dac_rx)); memcpy(fb->dac1, &mq1_quad.dac1, sizeof(dac_rx)); @@ -93,17 +105,21 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) break; } default: { - deallocate_MQ1_fields(*mq1_header); - free(header); - header = NULL; - free(mq1_header); - mq1_header = NULL; fprintf(stderr, "headersize not 384 or 768\n"); - return; + goto cleanup; } } - free(header); - header = NULL; + +cleanup: + if (header) { + free(header); + header = NULL; + } + if (mq1_header) { + free(mq1_header); + mq1_header = NULL; + deallocate_MQ1_fields(*mq1_header); + } } void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) From 220cfcf0fabd013b8c39eceb5dfd223938176c81 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 14:13:05 +0100 Subject: [PATCH 129/251] move convrt endian logics to utils --- src/read.c | 20 +++++--------------- src/read.h | 5 ----- src/utils.h | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/read.c b/src/read.c index b2f807e..8b4e01f 100644 --- a/src/read.c +++ b/src/read.c @@ -168,7 +168,7 @@ void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) return; } - size_t status = fread(raw_data, sizeof(char), bufsize * detx * dety, mib_ptr); + int status = fread(raw_data, sizeof(char), bufsize * detx * dety, mib_ptr); if (status != bufsize * detx * dety) { fprintf(stderr, "fread error in read_frame\n"); return; @@ -178,32 +178,22 @@ void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) for (int j = 0; j < detx; j++) { size_t index = (i * detx + j) * bufsize; uint8_t *raw_bytes = &raw_data[index]; - uint64_t value = 0; switch (bufsize) { case 1: { - value = raw_bytes[0]; - ((uint8_t **) fb->rows)[i][j] = (uint8_t) value; + ((uint8_t **) fb->rows)[i][j] = raw_bytes[0]; break; } case 2: { - value = (raw_bytes[0] << 8) | raw_bytes[1]; - ((uint16_t **) fb->rows)[i][j] = (uint16_t) value; + ((uint16_t **) fb->rows)[i][j] = convert_uint16_be(raw_bytes); break; } case 4: { - value = (raw_bytes[0] << 24) | (raw_bytes[1] << 16) | - (raw_bytes[2] << 8) | raw_bytes[3]; - ((uint32_t **) fb->rows)[i][j] = (uint32_t) value; + ((uint32_t **) fb->rows)[i][j] = convert_uint32_be(raw_bytes); break; } case 8: { - value = - ((uint64_t) raw_bytes[0] << 56) | ((uint64_t) raw_bytes[1] << 48) | - ((uint64_t) raw_bytes[2] << 40) | ((uint64_t) raw_bytes[3] << 32) | - ((uint64_t) raw_bytes[4] << 24) | ((uint64_t) raw_bytes[5] << 16) | - ((uint64_t) raw_bytes[6] << 8) | ((uint64_t) raw_bytes[7]); - ((uint64_t **) fb->rows)[i][j] = value; + ((uint64_t **) fb->rows)[i][j] = convert_uint64_be(raw_bytes); break; } default: { diff --git a/src/read.h b/src/read.h index 49a159c..debca00 100644 --- a/src/read.h +++ b/src/read.h @@ -3,11 +3,6 @@ #define READ_H #include "framebuffer.h" -#include "io_header.h" -#include "macros.h" -#include "parser.h" -#include "utils.h" -#include void read_header(FILE *mib_ptr, long offset, framebuffer *fb); diff --git a/src/utils.h b/src/utils.h index f8cf3bb..817706b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,10 +1,30 @@ // clang-format Language: C #include +#include #include #ifndef UTILS_H #define UTILS_H +static inline uint16_t convert_uint16_be(const uint8_t *bytes) +{ + return ((uint16_t) bytes[0] << 8) | bytes[1]; +} + +static inline uint32_t convert_uint32_be(const uint8_t *bytes) +{ + return ((uint32_t) bytes[0] << 24) | ((uint32_t) bytes[1] << 16) | + ((uint32_t) bytes[2] << 8) | bytes[3]; +} + +static inline uint64_t convert_uint64_be(const uint8_t *bytes) +{ + return ((uint64_t) bytes[0] << 56) | ((uint64_t) bytes[1] << 48) | + ((uint64_t) bytes[2] << 40) | ((uint64_t) bytes[3] << 32) | + ((uint64_t) bytes[4] << 24) | ((uint64_t) bytes[5] << 16) | + ((uint64_t) bytes[6] << 8) | bytes[7]; +} + const char *only_file_name(const char *absolute_file_path); unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride); From 0080be6873e9ebd584455388f155dc97b5b36bfa Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 14:16:00 +0100 Subject: [PATCH 130/251] Fix deallocating null pointers --- src/read.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/read.c b/src/read.c index 8b4e01f..0542a60 100644 --- a/src/read.c +++ b/src/read.c @@ -116,9 +116,9 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) header = NULL; } if (mq1_header) { + deallocate_MQ1_fields(*mq1_header); free(mq1_header); mq1_header = NULL; - deallocate_MQ1_fields(*mq1_header); } } From 0110079e6095d7a899523cffb125bc604c2c057a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 14:20:15 +0100 Subject: [PATCH 131/251] fix potential uninit values --- src/read.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/read.c b/src/read.c index 0542a60..a20075a 100644 --- a/src/read.c +++ b/src/read.c @@ -15,6 +15,8 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) { + char *header; + MQ1_fields *mq1_header; if (mib_ptr == NULL || fb == NULL) { fprintf(stderr, "Missing input mib_ptr or fb in read_header\n"); goto cleanup; @@ -27,7 +29,6 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) fprintf(stderr, "fseek error in read_header\n"); goto cleanup; } - char buf[HEADER_LOC_IN_BUF] = {0}; char headersize_str[HEADERSIZE] = {0}; size_t status = fread(buf, sizeof(char), HEADER_LOC_IN_BUF, mib_ptr); @@ -49,12 +50,12 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) *end_ptr); goto cleanup; } - char *header = malloc(sizeof(char) * headersize); + *header = malloc(sizeof(char) * headersize); if (!header) { fprintf(stderr, "malloc fail for header in read_header\n"); goto cleanup; } - MQ1_fields *mq1_header = malloc(sizeof(MQ1_fields)); + *mq1_header = malloc(sizeof(MQ1_fields)); if (!mq1_header) { fprintf(stderr, "malloc fail for mq1_header in read_header\n"); goto cleanup; From 62a3d2c49c86fdb04adb3f9146cb6184eebbfdfe Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 14:21:52 +0100 Subject: [PATCH 132/251] Fix bugs --- src/read.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/read.c b/src/read.c index a20075a..cccf5f2 100644 --- a/src/read.c +++ b/src/read.c @@ -50,12 +50,12 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) *end_ptr); goto cleanup; } - *header = malloc(sizeof(char) * headersize); + *header = (char *) malloc(sizeof(char) * headersize); if (!header) { fprintf(stderr, "malloc fail for header in read_header\n"); goto cleanup; } - *mq1_header = malloc(sizeof(MQ1_fields)); + *mq1_header = (MQ1_fields *) malloc(sizeof(MQ1_fields)); if (!mq1_header) { fprintf(stderr, "malloc fail for mq1_header in read_header\n"); goto cleanup; From dc38432fd37b6208c6bb54a2b3fce51ed169ae54 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 14:23:13 +0100 Subject: [PATCH 133/251] Fix typo --- src/read.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/read.c b/src/read.c index cccf5f2..9b12c6f 100644 --- a/src/read.c +++ b/src/read.c @@ -50,12 +50,12 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) *end_ptr); goto cleanup; } - *header = (char *) malloc(sizeof(char) * headersize); + header = (char *) malloc(sizeof(char) * headersize); if (!header) { fprintf(stderr, "malloc fail for header in read_header\n"); goto cleanup; } - *mq1_header = (MQ1_fields *) malloc(sizeof(MQ1_fields)); + mq1_header = (MQ1_fields *) malloc(sizeof(MQ1_fields)); if (!mq1_header) { fprintf(stderr, "malloc fail for mq1_header in read_header\n"); goto cleanup; From 4c26e6e244bb60fa0a2a4265fe4003b482117d7a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 14:27:46 +0100 Subject: [PATCH 134/251] Fix uninit variables --- src/read.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/read.c b/src/read.c index 9b12c6f..014402c 100644 --- a/src/read.c +++ b/src/read.c @@ -19,22 +19,22 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) MQ1_fields *mq1_header; if (mib_ptr == NULL || fb == NULL) { fprintf(stderr, "Missing input mib_ptr or fb in read_header\n"); - goto cleanup; + return; } if (offset < 0) { fprintf(stderr, "offset is negative, please check input\n"); - goto cleanup; + return; } if (fseek(mib_ptr, offset, SEEK_SET) != 0) { fprintf(stderr, "fseek error in read_header\n"); - goto cleanup; + return; } char buf[HEADER_LOC_IN_BUF] = {0}; char headersize_str[HEADERSIZE] = {0}; size_t status = fread(buf, sizeof(char), HEADER_LOC_IN_BUF, mib_ptr); if (status != HEADER_LOC_IN_BUF) { fprintf(stderr, "fread error in read_header\n"); - goto cleanup; + return; } memcpy(headersize_str, buf + HEADER_LOC_IN_BUF - HEADERSIZE + 1, HEADERSIZE - 1); @@ -43,22 +43,26 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) long unsigned int headersize = strtol(headersize_str, &end_ptr, 10); if (end_ptr == headersize_str) { fprintf(stderr, "headersize strtol error in read_header, no digit found\n"); - goto cleanup; + return; } else if (*end_ptr != '\0') { fprintf(stderr, "headersize strtol error in read_header, invalid character: %c\n", *end_ptr); - goto cleanup; + return; } header = (char *) malloc(sizeof(char) * headersize); if (!header) { fprintf(stderr, "malloc fail for header in read_header\n"); - goto cleanup; + return; } mq1_header = (MQ1_fields *) malloc(sizeof(MQ1_fields)); if (!mq1_header) { fprintf(stderr, "malloc fail for mq1_header in read_header\n"); - goto cleanup; + if (header) { + free(header); + header = NULL; + } + return; } *mq1_header = allocate_MQ1_fields(1); From c1b2f74cd893af0dc5f396f177df088988d777af Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 7 May 2025 15:10:35 +0100 Subject: [PATCH 135/251] Fix detangling pointers --- src/read.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/read.c b/src/read.c index 014402c..cfa5515 100644 --- a/src/read.c +++ b/src/read.c @@ -111,6 +111,11 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) } default: { fprintf(stderr, "headersize not 384 or 768\n"); + if (mq1_header) { + deallocate_MQ1_fields(*mq1_header); + free(mq1_header); + mq1_header = NULL; + } goto cleanup; } } @@ -120,11 +125,6 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) free(header); header = NULL; } - if (mq1_header) { - deallocate_MQ1_fields(*mq1_header); - free(mq1_header); - mq1_header = NULL; - } } void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) From aa0932937b51287818a3f49c3f3cae79ee862871 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 8 May 2025 12:55:54 +0100 Subject: [PATCH 136/251] Fix typo in fprintf --- src/hdf5_init_meta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 33aaa40..5960ff1 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -66,7 +66,7 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) header_id_type = H5Tcopy(H5T_C_S1); if (header_id_type < 0) { - fprintf(stderr, "H5Tcopt failed for header_id_type\n"); + fprintf(stderr, "H5Tcopy failed for header_id_type\n"); goto cleanup; } if (H5Tset_size(header_id_type, MQ1_CHAR_LEN_HEADER_ID) < 0) { From 2e260146102e3a3dc521979baed91bfc709c5568 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 8 May 2025 12:56:22 +0100 Subject: [PATCH 137/251] Modify order for deallocation --- src/hdf5_init_meta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index 5960ff1..a7f08e8 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -193,8 +193,6 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) } cleanup: - if (H5Iis_valid(header_id_type)) - H5Tclose(header_id_type); if (H5Iis_valid(threshold_type)) H5Tclose(threshold_type); if (H5Iis_valid(extended_timestamp_type)) @@ -209,6 +207,8 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) H5Tclose(sensor_layout_type); if (H5Iis_valid(pixel_depth_type)) H5Tclose(pixel_depth_type); + if (H5Iis_valid(header_id_type)) + H5Tclose(header_id_type); if (H5Iis_valid(dapl)) H5Pclose(dapl); if (H5Iis_valid(dcpl)) From 78c041cf71a9dd5e17d725a94022382b191695a7 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 12 May 2025 09:47:17 +0100 Subject: [PATCH 138/251] change strtol to strtoul --- src/read.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/read.c b/src/read.c index cfa5515..b9a982a 100644 --- a/src/read.c +++ b/src/read.c @@ -40,7 +40,7 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) HEADERSIZE - 1); headersize_str[HEADERSIZE - 1] = '\0'; char *end_ptr; - long unsigned int headersize = strtol(headersize_str, &end_ptr, 10); + long unsigned int headersize = strtoul(headersize_str, &end_ptr, 10); if (end_ptr == headersize_str) { fprintf(stderr, "headersize strtol error in read_header, no digit found\n"); return; From ab05e68ba04a869056b59ade77aaf4be0e56f32f Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 12 May 2025 09:56:22 +0100 Subject: [PATCH 139/251] Change to use macros.h for headersize --- src/macros.h | 6 ++++++ src/read.c | 18 ++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/macros.h b/src/macros.h index 3e67106..e74389a 100644 --- a/src/macros.h +++ b/src/macros.h @@ -36,4 +36,10 @@ #define ALIGNMENT_THRESHOLD 512 +#define MIB_HEADER_SIZE_FIELD_OFFSET 10 + +#define MIB_HEADER_SIZE_FIELD_LENGTH 6 + +#define MIB_HEADER_METADATA_BUF_SIZE (MIB_HEADER_SIZE_FIELD_OFFSET + 6) + #endif diff --git a/src/read.c b/src/read.c index b9a982a..dde0c20 100644 --- a/src/read.c +++ b/src/read.c @@ -10,9 +10,6 @@ #include #include -#define HEADER_LOC_IN_BUF 16 -#define HEADERSIZE 6 - void read_header(FILE *mib_ptr, long offset, framebuffer *fb) { char *header; @@ -29,16 +26,17 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) fprintf(stderr, "fseek error in read_header\n"); return; } - char buf[HEADER_LOC_IN_BUF] = {0}; - char headersize_str[HEADERSIZE] = {0}; - size_t status = fread(buf, sizeof(char), HEADER_LOC_IN_BUF, mib_ptr); - if (status != HEADER_LOC_IN_BUF) { + char buf[MIB_HEADER_METADATA_BUF_SIZE] = {0}; + char headersize_str[MIB_HEADER_SIZE_FIELD_LENGTH] = {0}; + size_t status = + fread(buf, sizeof(char), MIB_HEADER_METADATA_BUF_SIZE, mib_ptr); + if (status != MIB_HEADER_METADATA_BUF_SIZE) { fprintf(stderr, "fread error in read_header\n"); return; } - memcpy(headersize_str, buf + HEADER_LOC_IN_BUF - HEADERSIZE + 1, - HEADERSIZE - 1); - headersize_str[HEADERSIZE - 1] = '\0'; + memcpy(headersize_str, buf + MIB_HEADER_SIZE_FIELD_OFFSET + 1, + MIB_HEADER_SIZE_FIELD_LENGTH - 1); + headersize_str[MIB_HEADER_SIZE_FIELD_LENGTH - 1] = '\0'; char *end_ptr; long unsigned int headersize = strtoul(headersize_str, &end_ptr, 10); if (end_ptr == headersize_str) { From e0ac6b7969efb68d5d0d27cf46a7fbf71b6f9479 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 12 May 2025 09:59:35 +0100 Subject: [PATCH 140/251] freeing raw_data in read_frame --- src/read.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/read.c b/src/read.c index dde0c20..693e83c 100644 --- a/src/read.c +++ b/src/read.c @@ -174,7 +174,7 @@ void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) int status = fread(raw_data, sizeof(char), bufsize * detx * dety, mib_ptr); if (status != bufsize * detx * dety) { fprintf(stderr, "fread error in read_frame\n"); - return; + goto cleanup; } for (int i = 0; i < dety; i++) { @@ -201,11 +201,12 @@ void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) } default: { fprintf(stderr, "not supported bufsize\n"); - return; + goto cleanup; } } } } +cleanup: free(raw_data); raw_data = NULL; } From b9afde2a9b9efce9eda0388e548de23083deac9b Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 12 May 2025 10:23:28 +0100 Subject: [PATCH 141/251] Change variables input to unsigned --- src/read.c | 4 ++-- src/read.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/read.c b/src/read.c index 693e83c..ac328c7 100644 --- a/src/read.c +++ b/src/read.c @@ -10,7 +10,7 @@ #include #include -void read_header(FILE *mib_ptr, long offset, framebuffer *fb) +void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) { char *header; MQ1_fields *mq1_header; @@ -125,7 +125,7 @@ void read_header(FILE *mib_ptr, long offset, framebuffer *fb) } } -void read_frame(FILE *mib_ptr, long offset, framebuffer *fb) +void read_frame(FILE *mib_ptr, unsigned long offset, framebuffer *fb) { if (!mib_ptr || !fb) { fprintf(stderr, "Missing input in read_frame\n"); diff --git a/src/read.h b/src/read.h index debca00..6a46d60 100644 --- a/src/read.h +++ b/src/read.h @@ -3,9 +3,10 @@ #define READ_H #include "framebuffer.h" +#include -void read_header(FILE *mib_ptr, long offset, framebuffer *fb); +void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb); -void read_frame(FILE *mib_ptr, long offset, framebuffer *fb); +void read_frame(FILE *mib_ptr, unsigned long offset, framebuffer *fb); #endif From e4119b75daf9638986ec1786c093834df56eec1f Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 12 May 2025 10:27:24 +0100 Subject: [PATCH 142/251] Add null check to fb->rows in read_frame --- src/read.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/read.c b/src/read.c index ac328c7..b1ec622 100644 --- a/src/read.c +++ b/src/read.c @@ -127,12 +127,14 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) void read_frame(FILE *mib_ptr, unsigned long offset, framebuffer *fb) { - if (!mib_ptr || !fb) { + if (!mib_ptr || !fb || !fb->rows) { fprintf(stderr, "Missing input in read_frame\n"); if (!mib_ptr) fprintf(stderr, "NO MIB_PTR\n"); if (!fb) fprintf(stderr, "NO fb\n"); + if (!fb->rows) + fprintf(stderr, "NO fb->rows\n"); return; } From 64938c8276fc5d103e9a9e30266f85f7cd9c727d Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 13 May 2025 10:00:04 +0100 Subject: [PATCH 143/251] Remove offset checking on negativity --- src/read.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/read.c b/src/read.c index b1ec622..8939888 100644 --- a/src/read.c +++ b/src/read.c @@ -18,10 +18,6 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) fprintf(stderr, "Missing input mib_ptr or fb in read_header\n"); return; } - if (offset < 0) { - fprintf(stderr, "offset is negative, please check input\n"); - return; - } if (fseek(mib_ptr, offset, SEEK_SET) != 0) { fprintf(stderr, "fseek error in read_header\n"); return; From f373fc5c745eb397b4f975fc446bbe994b1817d5 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 13 May 2025 13:13:54 +0100 Subject: [PATCH 144/251] Add checks on headersize --- src/read.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/read.c b/src/read.c index 8939888..e41fa60 100644 --- a/src/read.c +++ b/src/read.c @@ -44,6 +44,15 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) *end_ptr); return; } + + if (headersize != MQ1_SINGLE_HEADER_BYTES || + headersize != MQ1_QUAD_HEADER_BYTES) { + fprintf( + stderr, + "headersize not equal to either single or quad header byte size.\n"); + return; + } + header = (char *) malloc(sizeof(char) * headersize); if (!header) { fprintf(stderr, "malloc fail for header in read_header\n"); From 09154444a812fc4c8c546fdd3d8340c913d96b6a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 13 May 2025 13:20:25 +0100 Subject: [PATCH 145/251] Remove unnecessary mq1_header --- src/read.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/read.c b/src/read.c index e41fa60..66e6c6e 100644 --- a/src/read.c +++ b/src/read.c @@ -13,7 +13,6 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) { char *header; - MQ1_fields *mq1_header; if (mib_ptr == NULL || fb == NULL) { fprintf(stderr, "Missing input mib_ptr or fb in read_header\n"); return; @@ -58,16 +57,6 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) fprintf(stderr, "malloc fail for header in read_header\n"); return; } - mq1_header = (MQ1_fields *) malloc(sizeof(MQ1_fields)); - if (!mq1_header) { - fprintf(stderr, "malloc fail for mq1_header in read_header\n"); - if (header) { - free(header); - header = NULL; - } - return; - } - *mq1_header = allocate_MQ1_fields(1); if (fseek(mib_ptr, offset, SEEK_SET) != 0) { fprintf(stderr, "fseek error in read_header\n"); @@ -92,8 +81,7 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) fb->dac1 = NULL; fb->dac2 = NULL; fb->dac3 = NULL; - fill_MQ1_single_fields(mq1_header, 0, mq1_single); - fb->mq1_header = mq1_header; + fill_MQ1_single_fields(fb->mq1_header, 0, mq1_single); break; } case MQ1_QUAD_HEADER_BYTES: { @@ -108,17 +96,11 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) memcpy(fb->dac1, &mq1_quad.dac1, sizeof(dac_rx)); memcpy(fb->dac2, &mq1_quad.dac2, sizeof(dac_rx)); memcpy(fb->dac3, &mq1_quad.dac3, sizeof(dac_rx)); - fill_MQ1_quad_fields(mq1_header, 0, mq1_quad); - fb->mq1_header = mq1_header; + fill_MQ1_quad_fields(fb->mq1_header, 0, mq1_quad); break; } default: { fprintf(stderr, "headersize not 384 or 768\n"); - if (mq1_header) { - deallocate_MQ1_fields(*mq1_header); - free(mq1_header); - mq1_header = NULL; - } goto cleanup; } } From 8b0d59840448ffbf953e9bb1369d3ddd221b2e92 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 13 May 2025 13:24:55 +0100 Subject: [PATCH 146/251] Fix fb->mq1_header Null check and typing --- src/read.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/read.c b/src/read.c index 66e6c6e..0630a62 100644 --- a/src/read.c +++ b/src/read.c @@ -114,14 +114,16 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) void read_frame(FILE *mib_ptr, unsigned long offset, framebuffer *fb) { - if (!mib_ptr || !fb || !fb->rows) { - fprintf(stderr, "Missing input in read_frame\n"); - if (!mib_ptr) - fprintf(stderr, "NO MIB_PTR\n"); - if (!fb) - fprintf(stderr, "NO fb\n"); - if (!fb->rows) - fprintf(stderr, "NO fb->rows\n"); + if (!mib_ptr) { + fprintf(stderr, "NO MIB_PTR\n"); + return; + } + if (!fb) { + fprintf(stderr, "NO fb\n"); + return; + } + if (!fb->rows) { + fprintf(stderr, "NO fb->rows\n"); return; } @@ -130,7 +132,7 @@ void read_frame(FILE *mib_ptr, unsigned long offset, framebuffer *fb) return; } else { if (fb->mq1_header->header_bytes == NULL || fb->mq1_header->det_x == NULL || - fb->mq1_header->det_y == NULL) { + fb->mq1_header->det_y == NULL || fb->mq1_header->pixel_depth == NULL) { fprintf(stderr, "NULL pointer inside fb->mq1_header in read_frame\n"); return; } @@ -146,8 +148,8 @@ void read_frame(FILE *mib_ptr, unsigned long offset, framebuffer *fb) return; } - int detx = (int) *(fb->mq1_header->det_x); - int dety = (int) *(fb->mq1_header->det_y); + int detx = *(fb->mq1_header->det_x); + int dety = *(fb->mq1_header->det_y); if (fseek(mib_ptr, offset + headersize, SEEK_SET) != 0) { fprintf(stderr, "fseek error in read_frame\n"); From 82e97ff8483295b3a334c543a6446f743af59388 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 15 May 2025 10:09:43 +0100 Subject: [PATCH 147/251] modify for clarity --- src/macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros.h b/src/macros.h index e74389a..87e8782 100644 --- a/src/macros.h +++ b/src/macros.h @@ -40,6 +40,6 @@ #define MIB_HEADER_SIZE_FIELD_LENGTH 6 -#define MIB_HEADER_METADATA_BUF_SIZE (MIB_HEADER_SIZE_FIELD_OFFSET + 6) +#define MIB_HEADER_METADATA_BUF_SIZE 16 #endif From f1d70331bd13bbf4cc920b700e30a91a6b50df96 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 15 May 2025 10:09:54 +0100 Subject: [PATCH 148/251] Fix logics error --- src/read.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/read.c b/src/read.c index 0630a62..7c0f8c5 100644 --- a/src/read.c +++ b/src/read.c @@ -44,7 +44,7 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) return; } - if (headersize != MQ1_SINGLE_HEADER_BYTES || + if (headersize != MQ1_SINGLE_HEADER_BYTES && headersize != MQ1_QUAD_HEADER_BYTES) { fprintf( stderr, From dab9d16f75f64b85770837e2b333eb7a8041791a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 15 May 2025 16:05:59 +0100 Subject: [PATCH 149/251] Freeing unused dac1, dac2, dac3 in single chip data --- src/read.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/read.c b/src/read.c index 7c0f8c5..78c0a92 100644 --- a/src/read.c +++ b/src/read.c @@ -78,8 +78,14 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) goto cleanup; } memcpy(fb->dac0, &mq1_single.dac0, sizeof(dac_rx)); + if (fb->dac1) + free(fb->dac1); fb->dac1 = NULL; + if (fb->dac2) + free(fb->dac2); fb->dac2 = NULL; + if (fb->dac3) + free(fb->dac3); fb->dac3 = NULL; fill_MQ1_single_fields(fb->mq1_header, 0, mq1_single); break; From 1974410dcfc7432477f165d8704afdfc6a26c1aa Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 15 May 2025 16:16:18 +0100 Subject: [PATCH 150/251] Remove freeing unused dac --- src/read.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/read.c b/src/read.c index 78c0a92..9956e1b 100644 --- a/src/read.c +++ b/src/read.c @@ -78,15 +78,6 @@ void read_header(FILE *mib_ptr, unsigned long offset, framebuffer *fb) goto cleanup; } memcpy(fb->dac0, &mq1_single.dac0, sizeof(dac_rx)); - if (fb->dac1) - free(fb->dac1); - fb->dac1 = NULL; - if (fb->dac2) - free(fb->dac2); - fb->dac2 = NULL; - if (fb->dac3) - free(fb->dac3); - fb->dac3 = NULL; fill_MQ1_single_fields(fb->mq1_header, 0, mq1_single); break; } From 47efd7664f41e7fc8ce05bb95b2741fbc4744e79 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 20 May 2025 09:39:01 +0100 Subject: [PATCH 151/251] Add logics to separate threshold into different fields --- src/hdf5_init_meta.c | 19 ++++---- src/io_header.c | 111 +++++++++++++++++++++++++++++++++++-------- src/io_header.h | 9 +++- src/macros.h | 2 +- 4 files changed, 109 insertions(+), 32 deletions(-) diff --git a/src/hdf5_init_meta.c b/src/hdf5_init_meta.c index a7f08e8..55902b5 100644 --- a/src/hdf5_init_meta.c +++ b/src/hdf5_init_meta.c @@ -15,8 +15,6 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) hid_t timestamp_type = H5I_INVALID_HID; hid_t header_extension_id_type = H5I_INVALID_HID; hid_t extended_timestamp_type = H5I_INVALID_HID; - hsize_t threshold_dims[1] = {MQ1_FLOAT_LEN_THRESHOLD}; - hid_t threshold_type = H5I_INVALID_HID; hid_t dataspace = H5I_INVALID_HID; hid_t dcpl = H5I_INVALID_HID; hid_t dapl = H5I_INVALID_HID; @@ -136,12 +134,6 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) goto cleanup; } - threshold_type = H5Tarray_create(H5T_NATIVE_FLOAT, 1, threshold_dims); - if (threshold_type < 0) { - fprintf(stderr, "H5Tarray_create failed for thresholds\n"); - goto cleanup; - } - struct { const char *name; hid_t type; @@ -161,7 +153,14 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) {"counter", H5T_NATIVE_UINT}, {"colour_mode", H5T_NATIVE_UINT}, {"gain_mode", H5T_NATIVE_UINT}, - {"threshold", threshold_type}, + {"threshold0", H5T_NATIVE_FLOAT}, + {"threshold1", H5T_NATIVE_FLOAT}, + {"threshold2", H5T_NATIVE_FLOAT}, + {"threshold3", H5T_NATIVE_FLOAT}, + {"threshold4", H5T_NATIVE_FLOAT}, + {"threshold5", H5T_NATIVE_FLOAT}, + {"threshold6", H5T_NATIVE_FLOAT}, + {"threshold7", H5T_NATIVE_FLOAT}, {"header_extension_id", header_extension_id_type}, {"extended_timestamp", extended_timestamp_type}, {"exposure_time_ns", H5T_NATIVE_UINT}, @@ -193,8 +192,6 @@ void create_meta_mq1_fields_dataset(hid_t file, hid_t lcpl, hid_t *meta_handle) } cleanup: - if (H5Iis_valid(threshold_type)) - H5Tclose(threshold_type); if (H5Iis_valid(extended_timestamp_type)) H5Tclose(extended_timestamp_type); if (H5Iis_valid(header_extension_id_type)) diff --git a/src/io_header.c b/src/io_header.c index 0e7c146..3e6fc7b 100644 --- a/src/io_header.c +++ b/src/io_header.c @@ -216,10 +216,52 @@ MQ1_fields allocate_MQ1_fields(unsigned int nheaders) } /*threshold is float[8]*/ - mq1_fields.threshold = (float *) malloc( - sizeof(float) * MQ1_FLOAT_LEN_THRESHOLD * mq1_fields.max_length); - if (mq1_fields.threshold == NULL) { - perror("Memory allocation error for threshold"); + mq1_fields.threshold0 = + (float *) malloc(sizeof(float) * mq1_fields.max_length); + if (mq1_fields.threshold0 == NULL) { + perror("Memory allocation error for threshold0"); + exit(1); + } + mq1_fields.threshold1 = + (float *) malloc(sizeof(float) * mq1_fields.max_length); + if (mq1_fields.threshold1 == NULL) { + perror("Memory allocation error for threshold1"); + exit(1); + } + mq1_fields.threshold2 = + (float *) malloc(sizeof(float) * mq1_fields.max_length); + if (mq1_fields.threshold2 == NULL) { + perror("Memory allocation error for threshold2"); + exit(1); + } + mq1_fields.threshold3 = + (float *) malloc(sizeof(float) * mq1_fields.max_length); + if (mq1_fields.threshold3 == NULL) { + perror("Memory allocation error for threshold3"); + exit(1); + } + mq1_fields.threshold4 = + (float *) malloc(sizeof(float) * mq1_fields.max_length); + if (mq1_fields.threshold4 == NULL) { + perror("Memory allocation error for threshold4"); + exit(1); + } + mq1_fields.threshold5 = + (float *) malloc(sizeof(float) * mq1_fields.max_length); + if (mq1_fields.threshold5 == NULL) { + perror("Memory allocation error for threshold5"); + exit(1); + } + mq1_fields.threshold6 = + (float *) malloc(sizeof(float) * mq1_fields.max_length); + if (mq1_fields.threshold6 == NULL) { + perror("Memory allocation error for threshold6"); + exit(1); + } + mq1_fields.threshold7 = + (float *) malloc(sizeof(float) * mq1_fields.max_length); + if (mq1_fields.threshold7 == NULL) { + perror("Memory allocation error for threshold7"); exit(1); } @@ -287,8 +329,22 @@ void deallocate_MQ1_fields(MQ1_fields mq1_fields) mq1_fields.colour_mode = NULL; free(mq1_fields.gain_mode); mq1_fields.gain_mode = NULL; - free(mq1_fields.threshold); - mq1_fields.threshold = NULL; + free(mq1_fields.threshold0); + mq1_fields.threshold0 = NULL; + free(mq1_fields.threshold1); + mq1_fields.threshold1 = NULL; + free(mq1_fields.threshold2); + mq1_fields.threshold2 = NULL; + free(mq1_fields.threshold3); + mq1_fields.threshold3 = NULL; + free(mq1_fields.threshold4); + mq1_fields.threshold4 = NULL; + free(mq1_fields.threshold5); + mq1_fields.threshold5 = NULL; + free(mq1_fields.threshold6); + mq1_fields.threshold6 = NULL; + free(mq1_fields.threshold7); + mq1_fields.threshold7 = NULL; free(mq1_fields.header_extension_id); mq1_fields.header_extension_id = NULL; free(mq1_fields.extended_timestamp); @@ -338,10 +394,15 @@ void fill_MQ1_single_fields(MQ1_fields *mq1_field, mq1_field->colour_mode[index] = mq1_h.colour_mode; mq1_field->gain_mode[index] = mq1_h.gain_mode; /*threshold is float[8]*/ - for (unsigned int i = 0; i < MQ1_FLOAT_LEN_THRESHOLD; ++i) { - mq1_field->threshold[index * MQ1_FLOAT_LEN_THRESHOLD + i] = - mq1_h.threshold[i]; - } + unsigned int i = -1; + mq1_field->threshold0[index] = mq1_h.threshold[++i]; + mq1_field->threshold1[index] = mq1_h.threshold[++i]; + mq1_field->threshold2[index] = mq1_h.threshold[++i]; + mq1_field->threshold3[index] = mq1_h.threshold[++i]; + mq1_field->threshold4[index] = mq1_h.threshold[++i]; + mq1_field->threshold5[index] = mq1_h.threshold[++i]; + mq1_field->threshold6[index] = mq1_h.threshold[++i]; + mq1_field->threshold7[index] = mq1_h.threshold[++i]; /*header_extension_id is char[5]*/ snprintf(mq1_field->header_extension_id + index * MQ1_CHAR_LEN_HEADER_EXTENSION_ID, @@ -391,10 +452,15 @@ void fill_MQ1_quad_fields(MQ1_fields *mq1_field, unsigned int index, mq1q mq1_h) mq1_field->colour_mode[index] = mq1_h.colour_mode; mq1_field->gain_mode[index] = mq1_h.gain_mode; /*threshold is float[8]*/ - for (unsigned int i = 0; i < MQ1_FLOAT_LEN_THRESHOLD; ++i) { - mq1_field->threshold[index * MQ1_FLOAT_LEN_THRESHOLD + i] = - mq1_h.threshold[i]; - } + unsigned int i = -1; + mq1_field->threshold0[index] = mq1_h.threshold[++i]; + mq1_field->threshold1[index] = mq1_h.threshold[++i]; + mq1_field->threshold2[index] = mq1_h.threshold[++i]; + mq1_field->threshold3[index] = mq1_h.threshold[++i]; + mq1_field->threshold4[index] = mq1_h.threshold[++i]; + mq1_field->threshold5[index] = mq1_h.threshold[++i]; + mq1_field->threshold6[index] = mq1_h.threshold[++i]; + mq1_field->threshold7[index] = mq1_h.threshold[++i]; /*header_extension_id is char[5]*/ snprintf(mq1_field->header_extension_id + index * MQ1_CHAR_LEN_HEADER_EXTENSION_ID, @@ -435,12 +501,19 @@ info *mq1_fields_info(MQ1_fields *fields_struct) fields[12] = (info) {"counter", fields_struct->counter}; fields[13] = (info) {"colour_mode", fields_struct->colour_mode}; fields[14] = (info) {"gain_mode", fields_struct->gain_mode}; - fields[15] = (info) {"threshold", fields_struct->threshold}; - fields[16] = + fields[15] = (info) {"threshold0", fields_struct->threshold0}; + fields[16] = (info) {"threshold1", fields_struct->threshold1}; + fields[17] = (info) {"threshold2", fields_struct->threshold2}; + fields[18] = (info) {"threshold3", fields_struct->threshold3}; + fields[19] = (info) {"threshold4", fields_struct->threshold4}; + fields[20] = (info) {"threshold5", fields_struct->threshold5}; + fields[21] = (info) {"threshold6", fields_struct->threshold6}; + fields[22] = (info) {"threshold7", fields_struct->threshold7}; + fields[23] = (info) {"header_extension_id", fields_struct->header_extension_id}; - fields[17] = (info) {"extended_timestamp", fields_struct->extended_timestamp}; - fields[18] = (info) {"exposure_time_ns", fields_struct->exposure_time_ns}; - fields[19] = (info) {"bit_depth", fields_struct->bit_depth}; + fields[24] = (info) {"extended_timestamp", fields_struct->extended_timestamp}; + fields[25] = (info) {"exposure_time_ns", fields_struct->exposure_time_ns}; + fields[26] = (info) {"bit_depth", fields_struct->bit_depth}; return fields; } diff --git a/src/io_header.h b/src/io_header.h index 753455b..6188456 100644 --- a/src/io_header.h +++ b/src/io_header.h @@ -24,7 +24,14 @@ typedef struct { unsigned int *counter; unsigned int *colour_mode; unsigned int *gain_mode; - float *threshold; + float *threshold0; + float *threshold1; + float *threshold2; + float *threshold3; + float *threshold4; + float *threshold5; + float *threshold6; + float *threshold7; char *header_extension_id; char *extended_timestamp; unsigned int *exposure_time_ns; diff --git a/src/macros.h b/src/macros.h index 2eb885e..1fe0ea3 100644 --- a/src/macros.h +++ b/src/macros.h @@ -26,7 +26,7 @@ #define MQ1_CHAR_LEN_EXTENDED_TIMESTAMP 31 -#define MQ1_FIELDS_NUM_FIELDS 20 +#define MQ1_FIELDS_NUM_FIELDS 27 #define DAC_NUM_FIELDS 28 From 5b3d69bc13c6525786bcf90d36398caa9bdeb87b Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 20 May 2025 10:15:15 +0100 Subject: [PATCH 152/251] Add logics to compress with blosc and hdf5-blosc --- src/compress.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ src/compress.h | 18 +++++++ src/hdf5_init.c | 16 +----- src/hdf5_init.h | 1 + 4 files changed, 155 insertions(+), 15 deletions(-) create mode 100644 src/compress.c create mode 100644 src/compress.h diff --git a/src/compress.c b/src/compress.c new file mode 100644 index 0000000..a17051d --- /dev/null +++ b/src/compress.c @@ -0,0 +1,135 @@ +#include "config.h" +#include "framebuffer.h" +#include "io_header.h" +#include "macros.h" +#include "mib_header.h" +#include "utils.h" +#include +#include +#include + +#ifdef HAVE_COMPRESSION +#include +#include +#endif + +hid_t dcpl_compress(size_t dim, + hsize_t *frame_dim, + unsigned int compression_level, + unsigned int shuffle, + char *compressor) +{ + hid_t dcpl = H5I_INVALID_HID; + unsigned int cd_values[7] = {0}; + if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { + fprintf(stderr, "Error in creating dcpl\n"); + return H5I_INVALID_HID; + } else { + if (H5Pset_chunk(dcpl, dim, frame_dim) < 0) { + fprintf(stderr, "Error in H5Pset_chunk\n"); + return H5I_INVALID_HID; + } + if (H5Pset_fill_time(dcpl, H5D_FILL_TIME_NEVER) < 0) { + fprintf(stderr, "Error in H5Pset_fill_time\n"); + return H5I_INVALID_HID; + } +#ifdef HAVE_COMPRESSION + char *version = (char *) malloc(sizeof(char) * 512); + if (version == NULL) { + fprintf(stderr, "malloc for version failed\n"); + free(version); + return H5I_INVALID_HID; + } + char *date = (char *) malloc(sizeof(char) * 512); + if (date == NULL) { + fprintf(stderr, "malloc for date failed\n"); + free(version); + free(date); + return H5I_INVALID_HID; + } + cd_values[0] = 0; + cd_values[1] = 0; // compression_level; + cd_values[2] = 0; // shuffle; + cd_values[3] = 0; // blocksize + cd_values[4] = compression_level; // unused + cd_values[5] = shuffle; // unused + cd_values[6] = blosc_compname_to_compcode(compressor); + if (H5Pset_filter(dcpl, FILTER_BLOSC, H5Z_FLAG_OPTIONAL, 7, cd_values) < + 0) { + fprintf(stderr, "Error in H5Pset_filter\n"); + return H5I_INVALID_HID; + } + if (register_blosc(&version, &date) < 0) { + fprintf(stderr, "Error in register_blosc\n"); + free(version); + free(date); + return H5I_INVALID_HID; + } else { + printf("Blosc version info: %s (%s)\n", version, date); + } + free(version); + free(date); +#endif + } + return dcpl; +} + +int compress_frame(framebuffer *fb, + unsigned int compression_level, + unsigned int shuffle, + char *compressor, + size_t blocksize, + int numinternalthreads) +{ + int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + + (fb->mq1_header->pixel_depth[2] - '0'); + bufsize = bufsize / 8; + + int detx = (int) *(fb->mq1_header->det_x); + int dety = (int) *(fb->mq1_header->det_y); + + size_t nbytes = dety * detx * bufsize; +#ifdef HAVE_COMPRESSION + size_t destsize = nbytes + BLOSC_MAX_OVERHEAD; + void *dest = malloc(destsize); + if (!dest) { + fprintf(stderr, "Error in malloc for dest\n"); + return -1; + } + + cbytes = blosc_compress_ctx(compression_level, shuffle, bufsize, nbytes, + fb->data, dest, destsize, compressor, blocksize, + numinternalthreads); + + if (cbytes < 0) { + fprintf(stderr, "Error in blosc_compress\n"); + free(dest); + return -1; + } + if (cbytes == 0) { + fprintf(stderr, "Blosc returned 0 bytes (uncompressible?). Forcing " + "fallback to uncompressed write.\n"); + cbytes = nbytes; + return cbytes; + } + // for showing compression ratio in each frame, profiling purposes + // if (cbytes != 0) { + // printf("compression: %ld -> %d (%.1fx)\n", nbytes, cbytes, (1. * nbytes) / + // cbytes); + //} + + free(fb->data); + fb->data = malloc(destsize); + if (!fb->data) { + fprintf(stderr, "Error in malloc for fb->data\n"); + free(dest); + return -1; + } + + memcpy(fb->data, dest, cbytes); + free(dest); + return cbytes; +#else + return nbytes; +#endif +} diff --git a/src/compress.h b/src/compress.h new file mode 100644 index 0000000..c5ae65d --- /dev/null +++ b/src/compress.h @@ -0,0 +1,18 @@ +// clang-format Language: C +#ifndef COMPRESS_H +#define COMPRESS_H + +hid_t dcpl_compress(size_t dim, + hsize_t *frame_dim, + unsigned int compression_level, + unsigned int shuffle, + char *compressor); + +int compress_frame(framebuffer *fb, + unsigned int compression_level, + unsigned int shuffle, + char *compressor, + size_t blocksize, + int numinternalthreads); + +#endif diff --git a/src/hdf5_init.c b/src/hdf5_init.c index c49c256..b27365f 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -55,28 +55,14 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, char *merlin_dataset_name, int dtype, hid_t memspace, + hid_t dcpl, hid_t lcpl, size_t dim, hsize_t *frame_dim) { - hid_t dcpl = H5I_INVALID_HID; hid_t dapl = H5I_INVALID_HID; hid_t datatype = H5I_INVALID_HID; - if ((dcpl = H5Pcreate(H5P_DATASET_CREATE)) == H5I_INVALID_HID) { - fprintf(stderr, "Error in creating dcpl\n"); - goto cleanup; - } else { - if (H5Pset_chunk(dcpl, dim, frame_dim) < 0) { - fprintf(stderr, "Error in H5Pset_chunk\n"); - goto cleanup; - } - if (H5Pset_fill_time(dcpl, H5D_FILL_TIME_NEVER) < 0) { - fprintf(stderr, "Error in H5Pset_fill_time\n"); - goto cleanup; - } - } - if ((dapl = H5Pcreate(H5P_DATASET_ACCESS)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating dapl_id\n"); goto cleanup; diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 6038c06..6aff2c1 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -17,6 +17,7 @@ void create_merlin_dataset(hid_t *merlin_dataset_id, char *merlin_dataset_name, int dtype, hid_t memspace, + hid_t dcpl, hid_t lcpl, size_t dim, hsize_t *frame_dim); From 5713ea799ebc5a3f4ac75f78ed24616fc75858be Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 1 May 2025 15:18:40 +0100 Subject: [PATCH 153/251] Add in autotools file --- AUTHORS | 0 ChangeLog | 0 Makefile | 20 ------------------- Makefile.am | 1 + NEWS | 0 README | 1 + config.mk | 35 -------------------------------- configure.ac | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile.am | 3 +++ 9 files changed, 58 insertions(+), 55 deletions(-) create mode 100644 AUTHORS create mode 100644 ChangeLog delete mode 100644 Makefile create mode 100644 Makefile.am create mode 100644 NEWS create mode 120000 README delete mode 100644 config.mk create mode 100644 configure.ac create mode 100644 src/Makefile.am diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/Makefile b/Makefile deleted file mode 100644 index bd99ecc..0000000 --- a/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -include config.mk - -.PHONY: all clean - -all: $(TARGET) - -$(TARGET): $(OBJECTS) | $(BINDIR) - $(CC) $(OBJECTS) -o $@ $(LDFLAGS) - -$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) - $(CC) $(CFLAGS) -c $< -o $@ - -$(OBJDIR): - mkdir -p $(OBJDIR) - -$(BINDIR): - mkdir -p $(BINDIR) - -clean: - rm -rf $(OBJDIR)/*.o $(TARGET) diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..af437a6 --- /dev/null +++ b/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 120000 index 0000000..42061c0 --- /dev/null +++ b/README @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/config.mk b/config.mk deleted file mode 100644 index c04ba0c..0000000 --- a/config.mk +++ /dev/null @@ -1,35 +0,0 @@ -# === Directories === -SRCDIR := src -OBJDIR := obj -HDFDIR ?= $(HDF5_ROOT) - -BUILD ?= debug - -ifndef HDFDIR -$(error HDFDIR is not defined. Please set HDF5_ROOT or pass HDFDIR=...) -endif - -# === Compiler and flags === -CC := gcc - -ifeq ($(BUILD),debug) - CFLAGS := -Wall -Wextra -std=c11 -g -O0 -fanalyzer -else ifeq ($(BUILD),release) - CFLAGS := -Wall -Wextra -std=c11 -O2 -else ifeq ($(BUILD),asan) - CFLAGS := -Wall -Wextra -std=c11 -g -O0 -fsanitize=address - LDFLAGS += -fsanitize=address -else - $(error Unknown BUILD type: $(BUILD)) -endif - -CFLAGS += -I$(SRCDIR) -I$(HDFDIR)/include -LDFLAGS += -L$(HDFDIR)/lib -lhdf5 - -# === Sources === - -SOURCES := $(wildcard $(SRCDIR)/*.c) - -OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SOURCES)) - -TARGET := mib2h5 diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..96390fe --- /dev/null +++ b/configure.ac @@ -0,0 +1,53 @@ +AC_INIT([mib2h5], [1.5.2025], [teo.ching@diamond.ac.uk]) +AM_INIT_AUTOMAKE([-Wall foreign -Werror]) +AC_PROG_CC +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([Makefile src/Makefile]) + +# --- Build Type Options -- +AC_ARG_ENABLE([debug], + AS_HELP_STRING([--enable-debug], [Enable debug build (default: yes)]), + [debug_build=$enableval], [debug_build=yes]) + +AC_ARG_ENABLE([asan], + AS_HELP_STRING([--enable-asan], [Enable AddressSanitizer build]), + [asan_build=$enableval], [asan_build=no]) + +# --- External paths (can be passed as environment variables) --- +AC_ARG_VAR([HDFDIR], [Path to HDF5 installation]) +AC_ARG_VAR([BLOSCDIR], [Path to c-blosc installation]) +AC_ARG_VAR([HBDIR], [Path to hdf5-blosc installation]) + +# --- Set compiler flags based on build type --- +if test "$asan_build" = "yes"; then + CFLAGS="$CFLAGS -Wall -Wextra -std=c11 -g -O0 -fsanitize=address" + LDFLAGS="$LDFLAGS -fsanitize=address" +elif test "$debug_build" = "yes"; then + CFLAGS="$CFLAGS -Wall -Wextra -std=c11 -g -O0 -fanalyzer" +else + CFLAGS="$CFLAGS -Wall -Wextra -std=c11 -O2" +fi + +# --- Set preprocessor and linker paths based on environment variables --- +CPPFLAGS="$CPPFLAGS -I$HDFDIR/include -I$BLOSCDIR/include -I$HBDIR/src" +LDFLAGS="$LDFLAGS -L$HDFDIR/lib -L$BLOSCDIR/lib64 -L$HBDIR/build -Wl,-rpath=${BLOSCDIR}/lib64 -Wl,-rpath=${HBDIR}/build" + +# --- Check for HDF5 --- +AC_CHECK_HEADER([hdf5.h], [], + [AC_MSG_ERROR([Missing hdf5.h. Set HDFDIR correctly to the HDF5 install path.])]) +AC_CHECK_LIB([hdf5], [H5open], [], + [AC_MSG_ERROR([Missing libhdf5. Set HDFDIR correctly to the HDF5 install path.])]) + +# --- Check for BLOSC --- +AC_CHECK_HEADER([blosc.h], [], + [AC_MSG_ERROR([Missing blosc.h. Set BLOSCDIR correctly to the BLOSC install path.])]) +AC_CHECK_LIB([blosc], [blosc_init], [], + [AC_MSG_ERROR([Missing libblosc. Set BLOSCDIR correctly to the BLOSC install path.])]) + +# --- Check for hdf5-blosc --- +AC_CHECK_HEADER([blosc_filter.h], [], + [AC_MSG_ERROR([Missing blosc_filter.h. Set HBDIR correctly to the hdf5-blosc source path.])]) +AC_CHECK_LIB([blosc_filter], [register_blosc], [], + [AC_MSG_ERROR([Missing libblosc_filter. Set HBDIR correctly to the hdf5-blosc build path.])]) + +AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..b2f07b1 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,3 @@ +bin_PROGRAMS = mib2h5 + +mib2h5_SOURCES = main.c utils.c io_header.c parser.c framebuffer.c hdf5_init.c hdf5_init_meta.c read.c append.c From c3e4b308ef218db626a7f724c42a41263e35b67a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 8 May 2025 12:46:28 +0100 Subject: [PATCH 154/251] Add logics to let user provide path for hdf5, blosc, and hdf5-blosc This will let users to provide custom path for these dependencies. --with-hdf5: provided path: use this not provided: detect in system path, if no then abort --with-compression: provided: indicate the need for checking blosc and hdf5-blosc not provided: not compiling with those libraries --with-blosc, --with-hdf5-blosc: provided path: use this path for those libraries not provided: if --with-compression is stated, check system path, if no then abort --- configure.ac | 126 ++++++++++++++++++++++++++++++++++++------------ src/Makefile.am | 3 ++ 2 files changed, 97 insertions(+), 32 deletions(-) diff --git a/configure.ac b/configure.ac index 96390fe..0d74b91 100644 --- a/configure.ac +++ b/configure.ac @@ -1,22 +1,102 @@ -AC_INIT([mib2h5], [1.5.2025], [teo.ching@diamond.ac.uk]) -AM_INIT_AUTOMAKE([-Wall foreign -Werror]) -AC_PROG_CC -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_FILES([Makefile src/Makefile]) +AC_INIT([mib2h5], [0.0.1], [https://github.com/ePSIC-DLS/mib2h5], [mib2h5],[https://github.com/ePSIC-DLS/mib2h5]) +AM_INIT_AUTOMAKE([-Wall foreign -Werror tar-pax]) # --- Build Type Options -- AC_ARG_ENABLE([debug], - AS_HELP_STRING([--enable-debug], [Enable debug build (default: yes)]), + AS_HELP_STRING([--enable-debug], [Enable debug build]), [debug_build=$enableval], [debug_build=yes]) AC_ARG_ENABLE([asan], AS_HELP_STRING([--enable-asan], [Enable AddressSanitizer build]), [asan_build=$enableval], [asan_build=no]) -# --- External paths (can be passed as environment variables) --- -AC_ARG_VAR([HDFDIR], [Path to HDF5 installation]) -AC_ARG_VAR([BLOSCDIR], [Path to c-blosc installation]) -AC_ARG_VAR([HBDIR], [Path to hdf5-blosc installation]) +# --- Check for HDF5 --- + +AC_ARG_WITH([hdf5], + [AS_HELP_STRING([--with-hdf5=PATH], [Path to HDF5 installation])], + [HDFDIR="$withval"], + []) + +AS_IF([test -n "$HDFDIR"], [ + + # User gave --with-hdf5 — use it directly + CPPFLAGS="$CPPFLAGS -I$HDFDIR/include" + LDFLAGS="$LDFLAGS -L$HDFDIR/lib -Wl,-rpath=$HDFDIR/lib" + + AC_CHECK_HEADER([hdf5.h], [], [AC_MSG_ERROR([Missing hdf5.h in $HDFDIR/include])]) + AC_CHECK_LIB([hdf5], [H5open], [], [AC_MSG_ERROR([Missing libhdf5 in $HDFDIR/lib])]) + AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) +], +[ + # No --with-hdf5: try system-wide + AC_MSG_CHECKING([for system-wide HDF5 installation]) + AC_CHECK_HEADER([hdf5.h], [ + AC_CHECK_LIB([hdf5], [H5open], [ + AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) + ], [AC_MSG_ERROR([libhdf5 not found system-wide])]) + ], [AC_MSG_ERROR([hdf5.h not found system-wide])]) +]) + +# ---------------- Compression Option ---------------- +AC_ARG_WITH([compression], + [AS_HELP_STRING([--with-compression], [Enable compression with blosc and hdf5-blosc])], + [], + [with_compression=check]) + +AC_ARG_WITH([blosc], + [AS_HELP_STRING([--with-blosc=PATH], [Path to c-blosc installation])], + [BLOSCDIR="$withval"], + []) + +AC_ARG_WITH([hdf5-blosc], + [AS_HELP_STRING([--with-hdf5-blosc=PATH], [Path to hdf5-blosc installation])], + [HBDIR="$withval"], + []) + +AS_IF([test "x$with_compression" != xno], [ + + AC_MSG_NOTICE([Checking for Blosc compression support...]) + + # --- If user gave paths, use them directly --- + AS_IF([test -n "$BLOSCDIR" && test -n "$HBDIR"], [ + + CPPFLAGS="$CPPFLAGS -I$BLOSCDIR/include -I$HBDIR/src" + LDFLAGS="$LDFLAGS -L$BLOSCDIR/lib64 -L$HBDIR/build" + LDFLAGS="$LDFLAGS -Wl,-rpath=$BLOSCDIR/lib64 -Wl,-rpath=$HBDIR/build" + + AC_CHECK_HEADER([blosc.h], [], + [AC_MSG_ERROR([blosc.h not found in $BLOSCDIR/include])]) + AC_CHECK_LIB([blosc], [blosc_init], [], + [AC_MSG_ERROR([libblosc not found in $BLOSCDIR/lib64])]) + + AC_CHECK_HEADER([blosc_filter.h], [], + [AC_MSG_ERROR([blosc_filter.h not found in $HBDIR/src])]) + AC_CHECK_LIB([blosc_filter], [register_blosc], [], + [AC_MSG_ERROR([libblosc_filter not found in $HBDIR/build])]) + + AC_DEFINE([HAVE_COMPRESSION], [1], [Define if compression is enabled]) + AC_SUBST([LIBCOMPRESSION], ["-lblosc -lblosc_filter"]) + + ], [ + + # --- No user path: try system-wide --- + AC_CHECK_HEADER([blosc.h], [ + AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes]) + ]) + AC_CHECK_HEADER([blosc_filter.h], [ + AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes]) + ]) + + AS_IF([test "x$BLOSC_OK" = xyes && test "x$HDF5_BLOSC_OK" = xyes], [ + AC_DEFINE([HAVE_COMPRESSION], [1], [Define if compression is enabled]) + AC_SUBST([LIBCOMPRESSION], ["-lblosc -lblosc_filter"]) + ], [ + AS_IF([test "x$with_compression" != xcheck], [ + AC_MSG_FAILURE([Compression requested but blosc and hdf5-blosc not found system-wide, and no --with-blosc or --with-hdf5-blosc given]) + ]) + ]) + ]) +]) # --- Set compiler flags based on build type --- if test "$asan_build" = "yes"; then @@ -28,26 +108,8 @@ else CFLAGS="$CFLAGS -Wall -Wextra -std=c11 -O2" fi -# --- Set preprocessor and linker paths based on environment variables --- -CPPFLAGS="$CPPFLAGS -I$HDFDIR/include -I$BLOSCDIR/include -I$HBDIR/src" -LDFLAGS="$LDFLAGS -L$HDFDIR/lib -L$BLOSCDIR/lib64 -L$HBDIR/build -Wl,-rpath=${BLOSCDIR}/lib64 -Wl,-rpath=${HBDIR}/build" - -# --- Check for HDF5 --- -AC_CHECK_HEADER([hdf5.h], [], - [AC_MSG_ERROR([Missing hdf5.h. Set HDFDIR correctly to the HDF5 install path.])]) -AC_CHECK_LIB([hdf5], [H5open], [], - [AC_MSG_ERROR([Missing libhdf5. Set HDFDIR correctly to the HDF5 install path.])]) - -# --- Check for BLOSC --- -AC_CHECK_HEADER([blosc.h], [], - [AC_MSG_ERROR([Missing blosc.h. Set BLOSCDIR correctly to the BLOSC install path.])]) -AC_CHECK_LIB([blosc], [blosc_init], [], - [AC_MSG_ERROR([Missing libblosc. Set BLOSCDIR correctly to the BLOSC install path.])]) - -# --- Check for hdf5-blosc --- -AC_CHECK_HEADER([blosc_filter.h], [], - [AC_MSG_ERROR([Missing blosc_filter.h. Set HBDIR correctly to the hdf5-blosc source path.])]) -AC_CHECK_LIB([blosc_filter], [register_blosc], [], - [AC_MSG_ERROR([Missing libblosc_filter. Set HBDIR correctly to the hdf5-blosc build path.])]) - +AC_PROG_CC +AM_SILENT_RULES([yes]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index b2f07b1..b2eb71f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,6 @@ +# Target binary bin_PROGRAMS = mib2h5 +# Source files mib2h5_SOURCES = main.c utils.c io_header.c parser.c framebuffer.c hdf5_init.c hdf5_init_meta.c read.c append.c +mib2h5_LDADD = -lhdf5 @LIBCOMPRESSION@ From 26b4865a68fd0c18be40e08aa2063586df76236e Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 12 May 2025 12:12:30 +0100 Subject: [PATCH 155/251] Change the third argument to be issue page --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0d74b91..203d912 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([mib2h5], [0.0.1], [https://github.com/ePSIC-DLS/mib2h5], [mib2h5],[https://github.com/ePSIC-DLS/mib2h5]) +AC_INIT([mib2h5], [0.0.1], [https://github.com/ePSIC-DLS/mib2h5/issues], [mib2h5], [https://github.com/ePSIC-DLS/mib2h5]) AM_INIT_AUTOMAKE([-Wall foreign -Werror tar-pax]) # --- Build Type Options -- From f5e51bb615545b2cae33d8aa48c340fb2ccb9a1a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 12 May 2025 12:13:58 +0100 Subject: [PATCH 156/251] change default debug to no --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 203d912..a7e7231 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ AC_INIT([mib2h5], [0.0.1], [https://github.com/ePSIC-DLS/mib2h5/issues], [mib2h5], [https://github.com/ePSIC-DLS/mib2h5]) -AM_INIT_AUTOMAKE([-Wall foreign -Werror tar-pax]) +AM_INIT_AUTOMAKE([-Wall foreign -Werror tar-pax dist-xz]) # --- Build Type Options -- AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [Enable debug build]), - [debug_build=$enableval], [debug_build=yes]) + [debug_build=$enableval], [debug_build=no]) AC_ARG_ENABLE([asan], AS_HELP_STRING([--enable-asan], [Enable AddressSanitizer build]), From 66e43786ed04521a98386f9d82b1aeff93de6de2 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 12 May 2025 14:15:32 +0100 Subject: [PATCH 157/251] Modify configure.ac change difference typos, change different steps, and checking HDF5 paths --- configure.ac | 68 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/configure.ac b/configure.ac index a7e7231..2089443 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,8 @@ AC_INIT([mib2h5], [0.0.1], [https://github.com/ePSIC-DLS/mib2h5/issues], [mib2h5], [https://github.com/ePSIC-DLS/mib2h5]) AM_INIT_AUTOMAKE([-Wall foreign -Werror tar-pax dist-xz]) +AC_PROG_CC +AM_SILENT_RULES([yes]) +AC_CONFIG_HEADERS([config.h]) # --- Build Type Options -- AC_ARG_ENABLE([debug], @@ -17,8 +20,8 @@ AC_ARG_WITH([hdf5], [HDFDIR="$withval"], []) +AC_MSG_NOTICE([Check the path of --with-hdf5]) AS_IF([test -n "$HDFDIR"], [ - # User gave --with-hdf5 — use it directly CPPFLAGS="$CPPFLAGS -I$HDFDIR/include" LDFLAGS="$LDFLAGS -L$HDFDIR/lib -Wl,-rpath=$HDFDIR/lib" @@ -28,20 +31,53 @@ AS_IF([test -n "$HDFDIR"], [ AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) ], [ - # No --with-hdf5: try system-wide - AC_MSG_CHECKING([for system-wide HDF5 installation]) - AC_CHECK_HEADER([hdf5.h], [ - AC_CHECK_LIB([hdf5], [H5open], [ + # No --with-hdf5: try different common path + AC_MSG_NOTICE([Check the path of $HDF5_ROOT]) + AS_IF([test -n "$HDF5_ROOT"], [ + CPPFLAGS="$CPPFLAGS -I$HDF5_ROOT/include" + LDFLAGS="$LDFLAGS -L$HDF5_ROOT/lib -Wl,-rpath=$HDF5_ROOT/lib" + + AC_CHECK_HEADER([hdf5.h], [], [AC_MSG_ERROR([Missing hdf5.h in $HDF5_ROOT/include])]) + AC_CHECK_LIB([hdf5], [H5open], [], [AC_MSG_ERROR([Missing libhdf5 in $HDF5_ROOT/lib])]) + AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) + ], + [ + AC_MSG_NOTICE([Check the path of $HDF5_HOME]) + AS_IF([test -n "$HDF5_HOME"], [ + CPPFLAGS="$CPPFLAGS -I$HDF5_HOME/include" + LDFLAGS="$LDFLAGS -L$HDF5_HOME/lib -Wl,-rpath=$HDF5_HOME/lib" + + AC_CHECK_HEADER([hdf5.h], [], [AC_MSG_ERROR([Missing hdf5.h in $HDF5_HOME/include])]) + AC_CHECK_LIB([hdf5], [H5open], [], [AC_MSG_ERROR([Missing libhdf5 in $HDF5_HOME/lib])]) AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) - ], [AC_MSG_ERROR([libhdf5 not found system-wide])]) - ], [AC_MSG_ERROR([hdf5.h not found system-wide])]) + ], + [ + AC_MSG_NOTICE([Check the path of $HDF5_DIR]) + AS_IF([test -n "$HDF5_DIR"], [ + CPPFLAGS="$CPPFLAGS -I$HDF5_DIR/include" + LDFLAGS="$LDFLAGS -L$HDF5_DIR/lib -Wl,-rpath=$HDF5_DIR/lib" + + AC_CHECK_HEADER([hdf5.h], [], [AC_MSG_ERROR([Missing hdf5.h in $HDF5_DIR/include])]) + AC_CHECK_LIB([hdf5], [H5open], [], [AC_MSG_ERROR([Missing libhdf5 in $HDF5_DIR/lib])]) + AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) + ], + [ + AC_MSG_NOTICE([for system-wide HDF5 installation]) + AC_CHECK_HEADER([hdf5.h], [ + AC_CHECK_LIB([hdf5], [H5open], [ + AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) + ], [AC_MSG_ERROR([libhdf5 not found system-wide])]) + ], [AC_MSG_ERROR([hdf5.h not found system-wide])]) + ]) + ]) + ]) ]) # ---------------- Compression Option ---------------- -AC_ARG_WITH([compression], - [AS_HELP_STRING([--with-compression], [Enable compression with blosc and hdf5-blosc])], +AC_ARG_ENABLE([compression], + [AS_HELP_STRING([--enable-compression], [Enable compression with blosc and hdf5-blosc])], [], - [with_compression=check]) + [enable_compression=check]) AC_ARG_WITH([blosc], [AS_HELP_STRING([--with-blosc=PATH], [Path to c-blosc installation])], @@ -99,17 +135,15 @@ AS_IF([test "x$with_compression" != xno], [ ]) # --- Set compiler flags based on build type --- -if test "$asan_build" = "yes"; then + +AS_IF([test "x$asan_build" = "xyes"], [ CFLAGS="$CFLAGS -Wall -Wextra -std=c11 -g -O0 -fsanitize=address" LDFLAGS="$LDFLAGS -fsanitize=address" -elif test "$debug_build" = "yes"; then +], [test "x$debug_build" = "xyes"], [ CFLAGS="$CFLAGS -Wall -Wextra -std=c11 -g -O0 -fanalyzer" -else +], [ CFLAGS="$CFLAGS -Wall -Wextra -std=c11 -O2" -fi +]) -AC_PROG_CC -AM_SILENT_RULES([yes]) -AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT From 2c979c052d84ad0c8a8958e0ae8e69e88a70f9c5 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 12 May 2025 14:21:22 +0100 Subject: [PATCH 158/251] change silent rules to use m4_ifdef --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2089443..900cdff 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_INIT([mib2h5], [0.0.1], [https://github.com/ePSIC-DLS/mib2h5/issues], [mib2h5], [https://github.com/ePSIC-DLS/mib2h5]) AM_INIT_AUTOMAKE([-Wall foreign -Werror tar-pax dist-xz]) AC_PROG_CC -AM_SILENT_RULES([yes]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_CONFIG_HEADERS([config.h]) # --- Build Type Options -- From 9b553b69724cdc7500391a81a16a3fecdfcae8d8 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Tue, 13 May 2025 14:35:11 +0100 Subject: [PATCH 159/251] Modify logic to remove redundant code --- configure.ac | 70 +++++++++++++++++----------------------------------- 1 file changed, 23 insertions(+), 47 deletions(-) diff --git a/configure.ac b/configure.ac index 900cdff..89f2320 100644 --- a/configure.ac +++ b/configure.ac @@ -20,59 +20,35 @@ AC_ARG_WITH([hdf5], [HDFDIR="$withval"], []) -AC_MSG_NOTICE([Check the path of --with-hdf5]) -AS_IF([test -n "$HDFDIR"], [ - # User gave --with-hdf5 — use it directly - CPPFLAGS="$CPPFLAGS -I$HDFDIR/include" - LDFLAGS="$LDFLAGS -L$HDFDIR/lib -Wl,-rpath=$HDFDIR/lib" - - AC_CHECK_HEADER([hdf5.h], [], [AC_MSG_ERROR([Missing hdf5.h in $HDFDIR/include])]) - AC_CHECK_LIB([hdf5], [H5open], [], [AC_MSG_ERROR([Missing libhdf5 in $HDFDIR/lib])]) - AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) -], -[ - # No --with-hdf5: try different common path - AC_MSG_NOTICE([Check the path of $HDF5_ROOT]) - AS_IF([test -n "$HDF5_ROOT"], [ - CPPFLAGS="$CPPFLAGS -I$HDF5_ROOT/include" - LDFLAGS="$LDFLAGS -L$HDF5_ROOT/lib -Wl,-rpath=$HDF5_ROOT/lib" - - AC_CHECK_HEADER([hdf5.h], [], [AC_MSG_ERROR([Missing hdf5.h in $HDF5_ROOT/include])]) - AC_CHECK_LIB([hdf5], [H5open], [], [AC_MSG_ERROR([Missing libhdf5 in $HDF5_ROOT/lib])]) - AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) - ], - [ - AC_MSG_NOTICE([Check the path of $HDF5_HOME]) - AS_IF([test -n "$HDF5_HOME"], [ - CPPFLAGS="$CPPFLAGS -I$HDF5_HOME/include" - LDFLAGS="$LDFLAGS -L$HDF5_HOME/lib -Wl,-rpath=$HDF5_HOME/lib" - - AC_CHECK_HEADER([hdf5.h], [], [AC_MSG_ERROR([Missing hdf5.h in $HDF5_HOME/include])]) - AC_CHECK_LIB([hdf5], [H5open], [], [AC_MSG_ERROR([Missing libhdf5 in $HDF5_HOME/lib])]) - AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) - ], - [ - AC_MSG_NOTICE([Check the path of $HDF5_DIR]) - AS_IF([test -n "$HDF5_DIR"], [ - CPPFLAGS="$CPPFLAGS -I$HDF5_DIR/include" - LDFLAGS="$LDFLAGS -L$HDF5_DIR/lib -Wl,-rpath=$HDF5_DIR/lib" - - AC_CHECK_HEADER([hdf5.h], [], [AC_MSG_ERROR([Missing hdf5.h in $HDF5_DIR/include])]) - AC_CHECK_LIB([hdf5], [H5open], [], [AC_MSG_ERROR([Missing libhdf5 in $HDF5_DIR/lib])]) +AS_IF([test -z "$HDFDIR"], [ + AC_MSG_NOTICE([--with-hdf5 not provided, checking common HDF5 environment variables...]) + AS_IF([test -n "$HDF5_ROOT"], [possible_hdf5_path="$HDF5_ROOT"]) + AS_IF([test -z "$possible_hdf5_path" && test -n "$HDF5_HOME"], [possible_hdf5_path="$HDF5_HOME"]) + AS_IF([test -z "$possible_hdf5_path" && test -n "$HDF5_DIR"], [possible_hdf5_path="$HDF5_DIR"]) + + AS_IF([test -n "$possible_hdf5_path"], [ + AC_MSG_NOTICE([Trying HDF5 from $possible_hdf5_path]) + CPPFLAGS="$CPPFLAGS -I$possible_hdf5_path/include" + LDFLAGS="$LDFLAGS -L$possible_hdf5_path/lib -Wl,-rpath=$possible_hdf5_path/lib" + AC_CHECK_HEADER([hdf5.h], [ + AC_CHECK_LIB([hdf5], [H5open], [ AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) - ], - [ - AC_MSG_NOTICE([for system-wide HDF5 installation]) - AC_CHECK_HEADER([hdf5.h], [ - AC_CHECK_LIB([hdf5], [H5open], [ - AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) - ], [AC_MSG_ERROR([libhdf5 not found system-wide])]) - ], [AC_MSG_ERROR([hdf5.h not found system-wide])]) + HDFDIR="$possible_hdf5_path" ]) ]) ]) ]) +# Final fallback: try system-wide +AS_IF([test -z "$HDFDIR"], [ + AC_MSG_NOTICE([Trying system-wide HDF5 installation]) + AC_CHECK_HEADER([hdf5.h], [ + AC_CHECK_LIB([hdf5], [H5open], [ + AC_DEFINE([HAVE_HDF5], [1], [Define if system HDF5 is available]) + ], [AC_MSG_ERROR([libhdf5 not found system-wide])]) + ], [AC_MSG_ERROR([hdf5.h not found system-wide])]) +]) + # ---------------- Compression Option ---------------- AC_ARG_ENABLE([compression], [AS_HELP_STRING([--enable-compression], [Enable compression with blosc and hdf5-blosc])], From 430a86e2186fa9bbe06c97f4933f6da6aac80172 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 15 May 2025 10:19:54 +0100 Subject: [PATCH 160/251] Change with-compression to enable-compression --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 89f2320..c76143d 100644 --- a/configure.ac +++ b/configure.ac @@ -65,7 +65,7 @@ AC_ARG_WITH([hdf5-blosc], [HBDIR="$withval"], []) -AS_IF([test "x$with_compression" != xno], [ +AS_IF([test "x$enable_compression" != xno], [ AC_MSG_NOTICE([Checking for Blosc compression support...]) @@ -103,7 +103,7 @@ AS_IF([test "x$with_compression" != xno], [ AC_DEFINE([HAVE_COMPRESSION], [1], [Define if compression is enabled]) AC_SUBST([LIBCOMPRESSION], ["-lblosc -lblosc_filter"]) ], [ - AS_IF([test "x$with_compression" != xcheck], [ + AS_IF([test "x$enable_compression" != xcheck], [ AC_MSG_FAILURE([Compression requested but blosc and hdf5-blosc not found system-wide, and no --with-blosc or --with-hdf5-blosc given]) ]) ]) From 9dce5dfad3db45fb0c5815d5b4e5ee59cf361afe Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 15 May 2025 14:47:57 +0100 Subject: [PATCH 161/251] Fix hdf5 not correctly detected when HDFDIR alredy set before the configuration --- configure.ac | 67 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/configure.ac b/configure.ac index c76143d..d9bfa48 100644 --- a/configure.ac +++ b/configure.ac @@ -20,33 +20,64 @@ AC_ARG_WITH([hdf5], [HDFDIR="$withval"], []) -AS_IF([test -z "$HDFDIR"], [ +HDF5_OK=no + +AS_IF([test -n "$HDFDIR"], [ + AC_MSG_NOTICE([Test HDFDIR provided]) + CPPFLAGS="$CPPFLAGS -I$HDFDIR/include" + LDFLAGS="$LDFLAGS -L$HDFDIR/lib" + + AC_CHECK_HEADER([hdf5.h], [ + AC_CHECK_LIB([hdf5], [H5open], [ + AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) + HDF5_OK=yes + ], [ + AC_MSG_NOTICE([libhdf5 not found on HDFDIR]) + HDF5_OK=no + ]) + ], [ + AC_MSG_NOTICE([hdf5.h not found on HDFDIR]) + HDF5_OK=no + ]) +]) + +AS_IF([test -z "$HDFDIR" || test "x$HDF5_OK" != xyes], [ AC_MSG_NOTICE([--with-hdf5 not provided, checking common HDF5 environment variables...]) - AS_IF([test -n "$HDF5_ROOT"], [possible_hdf5_path="$HDF5_ROOT"]) - AS_IF([test -z "$possible_hdf5_path" && test -n "$HDF5_HOME"], [possible_hdf5_path="$HDF5_HOME"]) - AS_IF([test -z "$possible_hdf5_path" && test -n "$HDF5_DIR"], [possible_hdf5_path="$HDF5_DIR"]) - - AS_IF([test -n "$possible_hdf5_path"], [ - AC_MSG_NOTICE([Trying HDF5 from $possible_hdf5_path]) - CPPFLAGS="$CPPFLAGS -I$possible_hdf5_path/include" - LDFLAGS="$LDFLAGS -L$possible_hdf5_path/lib -Wl,-rpath=$possible_hdf5_path/lib" + AS_IF([test -n "$HDF5_ROOT"], [HDFDIR="$HDF5_ROOT"]) + AS_IF([test -z "$HDFDIR" && test -n "$HDF5_HOME"], [HDFDIR="$HDF5_HOME"]) + AS_IF([test -z "$HDFDIR" && test -n "$HDF5_DIR"], [HDFDIR="$HDF5_DIR"]) + + AS_IF([test -n "$HDFDIR"], [ + AC_MSG_NOTICE([Trying HDF5 from $HDFDIR]) + CPPFLAGS="$CPPFLAGS -I$HDFDIR/include" + LDFLAGS="$LDFLAGS -L$HDFDIR/lib -Wl,-rpath=$HDFDIR/lib" AC_CHECK_HEADER([hdf5.h], [ AC_CHECK_LIB([hdf5], [H5open], [ AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) - HDFDIR="$possible_hdf5_path" + HDF5_OK=yes ]) ]) + ], [ + AC_MSG_NOTICE([Trying system-wide HDF5 installation]) + AC_CHECK_HEADER([hdf5.h], [ + AC_CHECK_LIB([hdf5], [H5open], [ + AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) + HDF5_OK=yes + ], [ + AC_MSG_NOTICE([libhdf5 not found system-wide]) + HDF5_OK=no + ]) + ], [ + AC_MSG_ERROR([hdf5.h not found system-wide]) + HDF5_OK=no + ]) ]) ]) -# Final fallback: try system-wide -AS_IF([test -z "$HDFDIR"], [ - AC_MSG_NOTICE([Trying system-wide HDF5 installation]) - AC_CHECK_HEADER([hdf5.h], [ - AC_CHECK_LIB([hdf5], [H5open], [ - AC_DEFINE([HAVE_HDF5], [1], [Define if system HDF5 is available]) - ], [AC_MSG_ERROR([libhdf5 not found system-wide])]) - ], [AC_MSG_ERROR([hdf5.h not found system-wide])]) +AS_IF([test "x$HDF5_OK" != xyes], [ + AC_MSG_ERROR([HDF5 not found]) +], [ + AC_MSG_NOTICE([HDF5 found in $HDFDIR]) ]) # ---------------- Compression Option ---------------- From 8c30a1ce1023eef19530cd68cd151ac671543e15 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 15 May 2025 14:48:14 +0100 Subject: [PATCH 162/251] Separate blosc and hdf5-blosc detection --- configure.ac | 56 +++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/configure.ac b/configure.ac index d9bfa48..d9b21d8 100644 --- a/configure.ac +++ b/configure.ac @@ -97,46 +97,44 @@ AC_ARG_WITH([hdf5-blosc], []) AS_IF([test "x$enable_compression" != xno], [ - AC_MSG_NOTICE([Checking for Blosc compression support...]) - # --- If user gave paths, use them directly --- - AS_IF([test -n "$BLOSCDIR" && test -n "$HBDIR"], [ - - CPPFLAGS="$CPPFLAGS -I$BLOSCDIR/include -I$HBDIR/src" - LDFLAGS="$LDFLAGS -L$BLOSCDIR/lib64 -L$HBDIR/build" - LDFLAGS="$LDFLAGS -Wl,-rpath=$BLOSCDIR/lib64 -Wl,-rpath=$HBDIR/build" - - AC_CHECK_HEADER([blosc.h], [], - [AC_MSG_ERROR([blosc.h not found in $BLOSCDIR/include])]) - AC_CHECK_LIB([blosc], [blosc_init], [], - [AC_MSG_ERROR([libblosc not found in $BLOSCDIR/lib64])]) - - AC_CHECK_HEADER([blosc_filter.h], [], - [AC_MSG_ERROR([blosc_filter.h not found in $HBDIR/src])]) - AC_CHECK_LIB([blosc_filter], [register_blosc], [], - [AC_MSG_ERROR([libblosc_filter not found in $HBDIR/build])]) - - AC_DEFINE([HAVE_COMPRESSION], [1], [Define if compression is enabled]) - AC_SUBST([LIBCOMPRESSION], ["-lblosc -lblosc_filter"]) + AS_IF([test -n "$BLOSCDIR"], [ + CPPFLAGS="$CPPFLAGS -I$BLOSCDIR/include" + LDFLAGS="$LDFLAGS -L$BLOSCDIR/lib64 -Wl,-rpath=$BLOSCDIR/lib64" + AC_CHECK_HEADER([blosc.h], [ + AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes], + [AC_MSG_ERROR([libblosc not found in $BLOSCDIR/lib64])]) + ], + [AC_MSG_ERROR([blosc.h not found in $BLOSCDIR/include])]) ], [ - - # --- No user path: try system-wide --- AC_CHECK_HEADER([blosc.h], [ AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes]) ]) + ]) + + AS_IF([test -n "$HBDIR"], [ + CPPFLAGS="$CPPFLAGS -I$HBDIR/src" + LDFLAGS="$LDFLAGS -L$HBDIR/build -Wl,-rpath=$HBDIR/build" + + AC_CHECK_HEADER([blosc_filter.h], [ + AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes], + [AC_MSG_ERROR([libblosc_filter not found in $HBDIR/build])]) + ], + [AC_MSG_ERROR([blosc_filter.h not found in $HBDIR/src])]) + ], [ AC_CHECK_HEADER([blosc_filter.h], [ AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes]) ]) + ]) - AS_IF([test "x$BLOSC_OK" = xyes && test "x$HDF5_BLOSC_OK" = xyes], [ - AC_DEFINE([HAVE_COMPRESSION], [1], [Define if compression is enabled]) - AC_SUBST([LIBCOMPRESSION], ["-lblosc -lblosc_filter"]) - ], [ - AS_IF([test "x$enable_compression" != xcheck], [ - AC_MSG_FAILURE([Compression requested but blosc and hdf5-blosc not found system-wide, and no --with-blosc or --with-hdf5-blosc given]) - ]) + AS_IF([test "x$BLOSC_OK" = xyes && test "x$HDF5_BLOSC_OK" = xyes], [ + AC_DEFINE([HAVE_COMPRESSION], [1], [Define if compression is enabled]) + AC_SUBST([LIBCOMPRESSION], ["-lblosc -lblosc_filter"]) + ], [ + AS_IF([test "x$enable_compression" != xcheck], [ + AC_MSG_FAILURE([Compression requested but blosc and hdf5-blosc not found system-wide, and no --with-blosc and --with-hdf5-blosc given]) ]) ]) ]) From df1988b84e1740e1bc69ba1e74041ade92dcf715 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 19 May 2025 11:40:26 +0100 Subject: [PATCH 163/251] Modify checking logics of HDF5 to make it more robust --- configure.ac | 79 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/configure.ac b/configure.ac index d9b21d8..a433bc9 100644 --- a/configure.ac +++ b/configure.ac @@ -33,51 +33,72 @@ AS_IF([test -n "$HDFDIR"], [ HDF5_OK=yes ], [ AC_MSG_NOTICE([libhdf5 not found on HDFDIR]) + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HDFDIR/include||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$HDFDIR/lib||g"`]) + $as_unset ac_cv_header_hdf5_h HDF5_OK=no ]) ], [ AC_MSG_NOTICE([hdf5.h not found on HDFDIR]) + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HDFDIR/include||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$HDFDIR/lib||g"`]) + $as_unset ac_cv_header_hdf5_h HDF5_OK=no ]) ]) -AS_IF([test -z "$HDFDIR" || test "x$HDF5_OK" != xyes], [ - AC_MSG_NOTICE([--with-hdf5 not provided, checking common HDF5 environment variables...]) - AS_IF([test -n "$HDF5_ROOT"], [HDFDIR="$HDF5_ROOT"]) - AS_IF([test -z "$HDFDIR" && test -n "$HDF5_HOME"], [HDFDIR="$HDF5_HOME"]) - AS_IF([test -z "$HDFDIR" && test -n "$HDF5_DIR"], [HDFDIR="$HDF5_DIR"]) - - AS_IF([test -n "$HDFDIR"], [ - AC_MSG_NOTICE([Trying HDF5 from $HDFDIR]) - CPPFLAGS="$CPPFLAGS -I$HDFDIR/include" - LDFLAGS="$LDFLAGS -L$HDFDIR/lib -Wl,-rpath=$HDFDIR/lib" - AC_CHECK_HEADER([hdf5.h], [ - AC_CHECK_LIB([hdf5], [H5open], [ - AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) - HDF5_OK=yes - ]) - ]) - ], [ - AC_MSG_NOTICE([Trying system-wide HDF5 installation]) - AC_CHECK_HEADER([hdf5.h], [ - AC_CHECK_LIB([hdf5], [H5open], [ - AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) - HDF5_OK=yes - ], [ - AC_MSG_NOTICE([libhdf5 not found system-wide]) - HDF5_OK=no - ]) +AS_IF([test "x$HDF5_OK" != xyes], [ + AC_MSG_NOTICE([Trying system-wide HDF5 installation]) + AC_CHECK_HEADER([hdf5.h], [ + AC_CHECK_LIB([hdf5], [H5open], [ + AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) + HDF5_OK=yes + AC_MSG_NOTICE([HDF5 found in system path]) ], [ - AC_MSG_ERROR([hdf5.h not found system-wide]) + AC_MSG_NOTICE([libhdf5 not found system-wide]) HDF5_OK=no + $as_unset ac_cv_header_hdf5_h ]) + ], [ + AC_MSG_NOTICE([hdf5.h not found system-wide]) + HDF5_OK=no + $as_unset ac_cv_header_hdf5_h ]) ]) +if test "x$HDF5_OK" != xyes; then + AC_MSG_NOTICE([--with-hdf5 not provided, checking common HDF5 environment variables...]) + for var in HDF5_ROOT HDF5_HOME HDF5_DIR; do + eval dir=\$$var + if test -n "$dir"; then + AC_MSG_NOTICE([Trying $var at $dir]) + CPPFLAGS="$CPPFLAGS -I$dir/include" + LDFLAGS="$LDFLAGS -L$dir/lib -Wl,-rpath=$dir/lib" + AC_CHECK_HEADER([hdf5.h], [ + AC_CHECK_LIB([hdf5], [H5open], [ + AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) + HDF5_OK=yes + HDFDIR="$dir" + AC_MSG_NOTICE([HDF5 found in $HDFDIR]) + ], [ + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$dir/include||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath=$dir/lib||g"`]) + HDF5_OK=no + $as_unset ac_cv_header_hdf5_h + ]) + ], [ + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$dir/include||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath=$dir/lib||g"`]) + HDF5_OK=no + $as_unset ac_cv_header_hdf5_h + ]) + test "x$HDF5_OK" = xyes && break + fi + done +fi + AS_IF([test "x$HDF5_OK" != xyes], [ AC_MSG_ERROR([HDF5 not found]) -], [ - AC_MSG_NOTICE([HDF5 found in $HDFDIR]) ]) # ---------------- Compression Option ---------------- From 517bfa3b4145fa0daccf19dd513a2c8cf8258891 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 19 May 2025 11:50:23 +0100 Subject: [PATCH 164/251] modify logics to check compression dependencies --- configure.ac | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index a433bc9..12cb7b8 100644 --- a/configure.ac +++ b/configure.ac @@ -118,35 +118,59 @@ AC_ARG_WITH([hdf5-blosc], []) AS_IF([test "x$enable_compression" != xno], [ + AC_MSG_NOTICE([Checking for Blosc compression support...]) + # --- If user gave paths, use them directly --- AS_IF([test -n "$BLOSCDIR"], [ CPPFLAGS="$CPPFLAGS -I$BLOSCDIR/include" LDFLAGS="$LDFLAGS -L$BLOSCDIR/lib64 -Wl,-rpath=$BLOSCDIR/lib64" AC_CHECK_HEADER([blosc.h], [ - AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes], - [AC_MSG_ERROR([libblosc not found in $BLOSCDIR/lib64])]) - ], - [AC_MSG_ERROR([blosc.h not found in $BLOSCDIR/include])]) - ], [ - AC_CHECK_HEADER([blosc.h], [ - AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes]) + AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes], [ + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$BLOSCDIR/include||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSCDIR/lib64||g; s|-Wl,-rpath=$BLOSCDIR/lib64||g"`]) + AC_MSG_NOTICE([libblosc not found in $BLOSCDIR/lib64]) + BLOSC_OK=no + ]) + ], [ + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$BLOSCDIR/include||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSCDIR/lib64||g; s|-Wl,-rpath=$BLOSCDIR/lib64||g"`]) + AC_MSG_NOTICE([blosc.h not found in $BLOSCDIR/include]) + BLOSC_OK=no ]) ]) + AS_IF([test "x$BLOSC_OK" != xyes], [ + AC_MSG_NOTICE([Falling back on system path for blosc]) + AC_CHECK_HEADER([blosc.h], [ + AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes], [BLOSC_OK=no]) + ], [BLOSC_OK=no]) + ]) + AS_IF([test -n "$HBDIR"], [ CPPFLAGS="$CPPFLAGS -I$HBDIR/src" LDFLAGS="$LDFLAGS -L$HBDIR/build -Wl,-rpath=$HBDIR/build" AC_CHECK_HEADER([blosc_filter.h], [ - AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes], - [AC_MSG_ERROR([libblosc_filter not found in $HBDIR/build])]) - ], - [AC_MSG_ERROR([blosc_filter.h not found in $HBDIR/src])]) - ], [ + AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes], [ + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/src||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/build||g; s|-Wl,-rpath=$HBDIR/build||g"`]) + AC_MSG_NOTICE([libblosc_filter not found in $HBDIR/build]) + HDF5_BLOSC_OK=no + ]) + ], [ + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/src||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/build||g; s|-Wl,-rpath=$HBDIR/build||g"`]) + AC_MSG_NOTICE([blosc_filter.h not found in $HBDIR/src]) + HDF5_BLOSC_OK=no + ]) + ]) + + AS_IF([test "x$HDF5_BLOSC_OK" != xyes], [ + AC_MSG_NOTICE([Falling back on system path for hdf5-blosc]) AC_CHECK_HEADER([blosc_filter.h], [ - AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes]) + AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes], [HDF5_BLOSC_OK=no]) ]) ]) From f815b93fbf6748118d2254f1bad800ca7e86fa7a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Mon, 19 May 2025 13:08:29 +0100 Subject: [PATCH 165/251] Remove GNU files --- AUTHORS => .jython_cache/packages/jython.pkc | 0 .jython_cache/packages/packages.idx | Bin 0 -> 240 bytes ChangeLog | 0 NEWS | 0 README | 1 - 5 files changed, 1 deletion(-) rename AUTHORS => .jython_cache/packages/jython.pkc (100%) create mode 100644 .jython_cache/packages/packages.idx delete mode 100644 ChangeLog delete mode 100644 NEWS delete mode 120000 README diff --git a/AUTHORS b/.jython_cache/packages/jython.pkc similarity index 100% rename from AUTHORS rename to .jython_cache/packages/jython.pkc diff --git a/.jython_cache/packages/packages.idx b/.jython_cache/packages/packages.idx new file mode 100644 index 0000000000000000000000000000000000000000..374afeed8488b34ae901f38d46e6388d00c31185 GIT binary patch literal 240 zcmYk!OAdlC6hKj25bxFUu}%#`2Syh_N~ur^Z9}P_p<8i9uE4~VXw;ZEyt&DVu2}aT zy-?B!iOpz(`=qz~2@8HSh2n!XH4fZQa>OdAzV`norjRfoaG-={B%5b3VQC)s%7hb~ zSYGBSx;`|@cnli2fci^9cb-~nN(u`|pqj_UdiO>sVPuKl2^}A!6}EPecoaHeX_8|h ky`HSY&9)p=McWL2l;EP3=(y0lk^W~mEuv_4xj&w_7f*dseE Date: Tue, 20 May 2025 13:59:53 +0100 Subject: [PATCH 166/251] Remove jython files --- .jython_cache/packages/jython.pkc | 0 .jython_cache/packages/packages.idx | Bin 240 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .jython_cache/packages/jython.pkc delete mode 100644 .jython_cache/packages/packages.idx diff --git a/.jython_cache/packages/jython.pkc b/.jython_cache/packages/jython.pkc deleted file mode 100644 index e69de29..0000000 diff --git a/.jython_cache/packages/packages.idx b/.jython_cache/packages/packages.idx deleted file mode 100644 index 374afeed8488b34ae901f38d46e6388d00c31185..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 240 zcmYk!OAdlC6hKj25bxFUu}%#`2Syh_N~ur^Z9}P_p<8i9uE4~VXw;ZEyt&DVu2}aT zy-?B!iOpz(`=qz~2@8HSh2n!XH4fZQa>OdAzV`norjRfoaG-={B%5b3VQC)s%7hb~ zSYGBSx;`|@cnli2fci^9cb-~nN(u`|pqj_UdiO>sVPuKl2^}A!6}EPecoaHeX_8|h ky`HSY&9)p=McWL2l;EP3=(y0lk^W~mEuv_4xj&w_7f*dseE Date: Wed, 21 May 2025 09:31:21 +0100 Subject: [PATCH 167/251] static inline function for malloc in utils --- src/utils.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/utils.h b/src/utils.h index 817706b..cec1a63 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,7 +1,10 @@ // clang-format Language: C +#include #include #include #include +#include +#include #ifndef UTILS_H #define UTILS_H @@ -25,6 +28,18 @@ static inline uint64_t convert_uint64_be(const uint8_t *bytes) ((uint64_t) bytes[6] << 8) | bytes[7]; } +static inline void *xmalloc_debug( + size_t size, const char *var, const char *func, const char *file, int line) +{ + void *ptr = malloc(size); + if (!ptr) { + fprintf(stderr, "[ERROR] malloc error for %s: %s (at %s:%d in %s)\n", var, + strerror(errno), file, line, func); + exit(1); + } + return ptr; +} + const char *only_file_name(const char *absolute_file_path); unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride); From 0430f89189b47dc178f59205ae3a282ff0fae724 Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Wed, 21 May 2025 10:50:52 +0100 Subject: [PATCH 168/251] change directory for checking hdf5-blosc --- configure.ac | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index 12cb7b8..9da803f 100644 --- a/configure.ac +++ b/configure.ac @@ -149,19 +149,19 @@ AS_IF([test "x$enable_compression" != xno], [ ]) AS_IF([test -n "$HBDIR"], [ - CPPFLAGS="$CPPFLAGS -I$HBDIR/src" - LDFLAGS="$LDFLAGS -L$HBDIR/build -Wl,-rpath=$HBDIR/build" + CPPFLAGS="$CPPFLAGS -I$HBDIR/include" + LDFLAGS="$LDFLAGS -L$HBDIR/lib -Wl,-rpath=$HBDIR/lib" AC_CHECK_HEADER([blosc_filter.h], [ AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes], [ - AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/src||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/build||g; s|-Wl,-rpath=$HBDIR/build||g"`]) + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/include||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/lib||g; s|-Wl,-rpath=$HBDIR/lib||g"`]) AC_MSG_NOTICE([libblosc_filter not found in $HBDIR/build]) HDF5_BLOSC_OK=no ]) ], [ - AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/src||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/build||g; s|-Wl,-rpath=$HBDIR/build||g"`]) + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/include||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/lib||g; s|-Wl,-rpath=$HBDIR/lib||g"`]) AC_MSG_NOTICE([blosc_filter.h not found in $HBDIR/src]) HDF5_BLOSC_OK=no ]) From 7553340877c36fbb205487da13770113b4129eec Mon Sep 17 00:00:00 2001 From: teoching0705 Date: Wed, 21 May 2025 15:59:07 +0100 Subject: [PATCH 169/251] Modify configure.ac to let it cross platform --- configure.ac | 69 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/configure.ac b/configure.ac index 9da803f..6905505 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,12 @@ +AC_PREREQ([2.69]) AC_INIT([mib2h5], [0.0.1], [https://github.com/ePSIC-DLS/mib2h5/issues], [mib2h5], [https://github.com/ePSIC-DLS/mib2h5]) AM_INIT_AUTOMAKE([-Wall foreign -Werror tar-pax dist-xz]) -AC_PROG_CC +AC_USE_SYSTEM_EXTENSIONS m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) +AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS([config.h]) +AC_CANONICAL_HOST +AC_PROG_CC # --- Build Type Options -- AC_ARG_ENABLE([debug], @@ -73,7 +77,7 @@ if test "x$HDF5_OK" != xyes; then if test -n "$dir"; then AC_MSG_NOTICE([Trying $var at $dir]) CPPFLAGS="$CPPFLAGS -I$dir/include" - LDFLAGS="$LDFLAGS -L$dir/lib -Wl,-rpath=$dir/lib" + LDFLAGS="$LDFLAGS -L$dir/lib -Wl,-rpath,$dir/lib" AC_CHECK_HEADER([hdf5.h], [ AC_CHECK_LIB([hdf5], [H5open], [ AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) @@ -82,13 +86,13 @@ if test "x$HDF5_OK" != xyes; then AC_MSG_NOTICE([HDF5 found in $HDFDIR]) ], [ AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$dir/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath=$dir/lib||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath,$dir/lib||g"`]) HDF5_OK=no $as_unset ac_cv_header_hdf5_h ]) ], [ AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$dir/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath=$dir/lib||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath,$dir/lib||g"`]) HDF5_OK=no $as_unset ac_cv_header_hdf5_h ]) @@ -105,7 +109,7 @@ AS_IF([test "x$HDF5_OK" != xyes], [ AC_ARG_ENABLE([compression], [AS_HELP_STRING([--enable-compression], [Enable compression with blosc and hdf5-blosc])], [], - [enable_compression=check]) + [enable_compression=no]) AC_ARG_WITH([blosc], [AS_HELP_STRING([--with-blosc=PATH], [Path to c-blosc installation])], @@ -120,27 +124,44 @@ AC_ARG_WITH([hdf5-blosc], AS_IF([test "x$enable_compression" != xno], [ AC_MSG_NOTICE([Checking for Blosc compression support...]) - # --- If user gave paths, use them directly --- - AS_IF([test -n "$BLOSCDIR"], [ - CPPFLAGS="$CPPFLAGS -I$BLOSCDIR/include" - LDFLAGS="$LDFLAGS -L$BLOSCDIR/lib64 -Wl,-rpath=$BLOSCDIR/lib64" - AC_CHECK_HEADER([blosc.h], [ - AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes], [ - AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$BLOSCDIR/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSCDIR/lib64||g; s|-Wl,-rpath=$BLOSCDIR/lib64||g"`]) - AC_MSG_NOTICE([libblosc not found in $BLOSCDIR/lib64]) + BLOSC_OK=no + + AS_IF([test -n "$BLOSCDIR"], [ + AS_IF([test -d "$BLOSCDIR/lib64"], [ + BLOSC_LIBDIR="$BLOSCDIR/lib64" + ], [ + AS_IF([test -d "$BLOSCDIR/lib"], [ + BLOSC_LIBDIR="$BLOSCDIR/lib" + ], [ + AC_MSG_NOTICE([Neither lib64 nor lib directory exists in $BLOSCDIR]) BLOSC_OK=no ]) - ], [ + ]) + ]) + + CPPFLAGS="$CPPFLAGS -I$BLOSCDIR/include" + LDFLAGS="$LDFLAGS -L$BLOSC_LIBDIR -Wl,-rpath,$BLOSC_LIBDIR" + + AC_CHECK_HEADER([blosc.h], [ + AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes], [ AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$BLOSCDIR/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSCDIR/lib64||g; s|-Wl,-rpath=$BLOSCDIR/lib64||g"`]) - AC_MSG_NOTICE([blosc.h not found in $BLOSCDIR/include]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSC_LIBDIR||g; s|-Wl,-rpath=$BLOSC_LIBDIR||g"`]) + AC_MSG_NOTICE([libblosc not found in $BLOSC_LIBDIR]) BLOSC_OK=no + $as_unset ac_cv_lib_blosc_blosc_init + $as_unset_ac_cv_header_blosc_h ]) + ], [ + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$BLOSCDIR/include||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSC_LIBDIR||g; s|-Wl,-rpath=$BLOSC_LIBDIR||g"`]) + AC_MSG_NOTICE([blosc.h not found in $BLOSCDIR/include]) + BLOSC_OK=no + $as_unset ac_cv_header_blosc_h ]) + AS_IF([test "x$BLOSC_OK" != xyes], [ AC_MSG_NOTICE([Falling back on system path for blosc]) AC_CHECK_HEADER([blosc.h], [ @@ -149,21 +170,23 @@ AS_IF([test "x$enable_compression" != xno], [ ]) AS_IF([test -n "$HBDIR"], [ - CPPFLAGS="$CPPFLAGS -I$HBDIR/include" - LDFLAGS="$LDFLAGS -L$HBDIR/lib -Wl,-rpath=$HBDIR/lib" + CPPFLAGS="$CPPFLAGS -I$HBDIR/src" + LDFLAGS="$LDFLAGS -L$HBDIR/build -Wl,-rpath,$HBDIR/build" AC_CHECK_HEADER([blosc_filter.h], [ AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes], [ - AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/lib||g; s|-Wl,-rpath=$HBDIR/lib||g"`]) + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/src||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/build||g; s|-Wl,-rpath,$HBDIR/build||g"`]) AC_MSG_NOTICE([libblosc_filter not found in $HBDIR/build]) HDF5_BLOSC_OK=no + $as_unset ac_cv_header_blosc_filter_h ]) ], [ - AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/lib||g; s|-Wl,-rpath=$HBDIR/lib||g"`]) + AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/src||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/build||g; s|-Wl,-rpath,$HBDIR/build||g"`]) AC_MSG_NOTICE([blosc_filter.h not found in $HBDIR/src]) HDF5_BLOSC_OK=no + $as_unset ac_cv_header_blosc_filter_h ]) ]) From ba3184e06eab47a611b38b472d0de7ab6917f5d2 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 21 May 2025 16:35:46 +0100 Subject: [PATCH 170/251] Use static inline function for malloc error declaration --- src/io_header.c | 200 +++++++++--------------------------------------- src/utils.h | 9 ++- 2 files changed, 44 insertions(+), 165 deletions(-) diff --git a/src/io_header.c b/src/io_header.c index 3e6fc7b..9986014 100644 --- a/src/io_header.c +++ b/src/io_header.c @@ -113,187 +113,63 @@ MQ1_fields allocate_MQ1_fields(unsigned int nheaders) mq1_fields.max_length = nheaders; - mq1_fields.header_id = (char *) malloc(sizeof(char) * MQ1_CHAR_LEN_HEADER_ID * - mq1_fields.max_length); - if (mq1_fields.header_id == NULL) { - perror("Memory allocation error for header id"); - exit(1); - } - + mq1_fields.header_id = XMALLOC( + sizeof(char) * MQ1_CHAR_LEN_HEADER_ID * mq1_fields.max_length, "header_id"); mq1_fields.sequence_number = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.sequence_number == NULL) { - perror("Memory allocation error for sequence number"); - exit(1); - } - + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "sequence_number"); mq1_fields.header_bytes = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.header_bytes == NULL) { - perror("Memory allocation error for header bytes"); - exit(1); - } - + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "header_bytes"); mq1_fields.num_chips = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.num_chips == NULL) { - perror("Memory allocation error for num chips"); - exit(1); - } - + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "num_chips"); mq1_fields.det_x = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.det_x == NULL) { - perror("Memory allocation error for det x"); - exit(1); - } - + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "det_x"); mq1_fields.det_y = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.det_y == NULL) { - perror("Memory allocation error for det y"); - exit(1); - } - - /*pixel_depth is char[4]*/ - mq1_fields.pixel_depth = (char *) malloc( - sizeof(char) * MQ1_CHAR_LEN_PIXEL_DEPTH * mq1_fields.max_length); - if (mq1_fields.pixel_depth == NULL) { - perror("Memory allocation error for pixel depth"); - exit(1); - } - - /*sensor_layout is char[7]*/ - mq1_fields.sensor_layout = (char *) malloc( - sizeof(char) * MQ1_CHAR_LEN_SENSOR_LAYOUT * mq1_fields.max_length); - if (mq1_fields.sensor_layout == NULL) { - perror("Memory allocation error for sensor layout"); - exit(1); - } - - /*chip_select is char[3]*/ - mq1_fields.chip_select = (char *) malloc( - sizeof(char) * MQ1_CHAR_LEN_CHIP_SELECT * mq1_fields.max_length); - if (mq1_fields.chip_select == NULL) { - perror("Memory allocation error for chip select"); - exit(1); - } - - /*timestamp is char[27]*/ - mq1_fields.timestamp = (char *) malloc(sizeof(char) * MQ1_CHAR_LEN_TIMESTAMP * - mq1_fields.max_length); - if (mq1_fields.timestamp == NULL) { - perror("Memory allocation error for timestamp"); - exit(1); - } - + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "det_y"); + mq1_fields.pixel_depth = + XMALLOC(sizeof(char) * MQ1_CHAR_LEN_PIXEL_DEPTH * mq1_fields.max_length, + "pixel_depth"); + mq1_fields.sensor_layout = + XMALLOC(sizeof(char) * MQ1_CHAR_LEN_SENSOR_LAYOUT * mq1_fields.max_length, + "sensor_layout"); + mq1_fields.chip_select = + XMALLOC(sizeof(char) * MQ1_CHAR_LEN_CHIP_SELECT * mq1_fields.max_length, + "chip_select"); + mq1_fields.timestamp = XMALLOC( + sizeof(char) * MQ1_CHAR_LEN_TIMESTAMP * mq1_fields.max_length, "timestamp"); mq1_fields.exposure_time_s = - (double *) malloc(sizeof(double) * mq1_fields.max_length); - if (mq1_fields.exposure_time_s == NULL) { - perror("Memory allocation error for exposure time s"); - exit(1); - } - + XMALLOC(sizeof(double) * mq1_fields.max_length, "exposure_time_s"); mq1_fields.counter = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.counter == NULL) { - perror("Memory allocation error for counter"); - exit(1); - } - + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "counter"); mq1_fields.colour_mode = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.colour_mode == NULL) { - perror("Memory allocation error for colour mode"); - exit(1); - } - + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "colour_mode"); mq1_fields.gain_mode = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.gain_mode == NULL) { - perror("Memory allocation error for gain mode"); - exit(1); - } - - /*threshold is float[8]*/ + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "gain_mode"); mq1_fields.threshold0 = - (float *) malloc(sizeof(float) * mq1_fields.max_length); - if (mq1_fields.threshold0 == NULL) { - perror("Memory allocation error for threshold0"); - exit(1); - } + XMALLOC(sizeof(float) * mq1_fields.max_length, "threshold0"); mq1_fields.threshold1 = - (float *) malloc(sizeof(float) * mq1_fields.max_length); - if (mq1_fields.threshold1 == NULL) { - perror("Memory allocation error for threshold1"); - exit(1); - } + XMALLOC(sizeof(float) * mq1_fields.max_length, "threshold1"); mq1_fields.threshold2 = - (float *) malloc(sizeof(float) * mq1_fields.max_length); - if (mq1_fields.threshold2 == NULL) { - perror("Memory allocation error for threshold2"); - exit(1); - } + XMALLOC(sizeof(float) * mq1_fields.max_length, "threshold2"); mq1_fields.threshold3 = - (float *) malloc(sizeof(float) * mq1_fields.max_length); - if (mq1_fields.threshold3 == NULL) { - perror("Memory allocation error for threshold3"); - exit(1); - } + XMALLOC(sizeof(float) * mq1_fields.max_length, "threshold3"); mq1_fields.threshold4 = - (float *) malloc(sizeof(float) * mq1_fields.max_length); - if (mq1_fields.threshold4 == NULL) { - perror("Memory allocation error for threshold4"); - exit(1); - } + XMALLOC(sizeof(float) * mq1_fields.max_length, "threshold4"); mq1_fields.threshold5 = - (float *) malloc(sizeof(float) * mq1_fields.max_length); - if (mq1_fields.threshold5 == NULL) { - perror("Memory allocation error for threshold5"); - exit(1); - } + XMALLOC(sizeof(float) * mq1_fields.max_length, "threshold5"); mq1_fields.threshold6 = - (float *) malloc(sizeof(float) * mq1_fields.max_length); - if (mq1_fields.threshold6 == NULL) { - perror("Memory allocation error for threshold6"); - exit(1); - } + XMALLOC(sizeof(float) * mq1_fields.max_length, "threshold6"); mq1_fields.threshold7 = - (float *) malloc(sizeof(float) * mq1_fields.max_length); - if (mq1_fields.threshold7 == NULL) { - perror("Memory allocation error for threshold7"); - exit(1); - } - - /*header_extension_id is char[5]*/ - mq1_fields.header_extension_id = (char *) malloc( - sizeof(char) * MQ1_CHAR_LEN_HEADER_EXTENSION_ID * mq1_fields.max_length); - if (mq1_fields.header_extension_id == NULL) { - perror("Memory allocation error for header extension id"); - exit(1); - } - - /*header_extension_id is char[31]*/ - mq1_fields.extended_timestamp = (char *) malloc( - sizeof(char) * MQ1_CHAR_LEN_EXTENDED_TIMESTAMP * mq1_fields.max_length); - if (mq1_fields.extended_timestamp == NULL) { - perror("Memory allocation error for extended timestamp"); - exit(1); - } - + XMALLOC(sizeof(float) * mq1_fields.max_length, "threshold7"); + mq1_fields.header_extension_id = XMALLOC( + sizeof(char) * MQ1_CHAR_LEN_HEADER_EXTENSION_ID * mq1_fields.max_length, + "header_extension_id"); + mq1_fields.extended_timestamp = XMALLOC( + sizeof(char) * MQ1_CHAR_LEN_EXTENDED_TIMESTAMP * mq1_fields.max_length, + "extended_timestamp"); mq1_fields.exposure_time_ns = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.exposure_time_ns == NULL) { - perror("Memory allocation error for exposure time ns"); - exit(1); - } - + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "exposure_time_ns"); mq1_fields.bit_depth = - (unsigned int *) malloc(sizeof(unsigned int) * mq1_fields.max_length); - if (mq1_fields.bit_depth == NULL) { - perror("Memory allocation error for bit depth"); - exit(1); - } + XMALLOC(sizeof(unsigned int) * mq1_fields.max_length, "bit_depth"); return mq1_fields; } diff --git a/src/utils.h b/src/utils.h index cec1a63..2da04f8 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,4 +1,7 @@ // clang-format Language: C +#ifndef UTILS_H +#define UTILS_H + #include #include #include @@ -6,9 +9,6 @@ #include #include -#ifndef UTILS_H -#define UTILS_H - static inline uint16_t convert_uint16_be(const uint8_t *bytes) { return ((uint16_t) bytes[0] << 8) | bytes[1]; @@ -40,6 +40,9 @@ static inline void *xmalloc_debug( return ptr; } +#define XMALLOC(size, var) \ + xmalloc_debug((size), (var), __func__, __FILE__, __LINE__) + const char *only_file_name(const char *absolute_file_path); unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride); From a58bc7030581178549658300b50e62fdd2a61ed6 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 08:33:33 +0100 Subject: [PATCH 171/251] Hard-code threshold index in io_header.c --- src/io_header.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/io_header.c b/src/io_header.c index 9986014..24e3af1 100644 --- a/src/io_header.c +++ b/src/io_header.c @@ -270,15 +270,14 @@ void fill_MQ1_single_fields(MQ1_fields *mq1_field, mq1_field->colour_mode[index] = mq1_h.colour_mode; mq1_field->gain_mode[index] = mq1_h.gain_mode; /*threshold is float[8]*/ - unsigned int i = -1; - mq1_field->threshold0[index] = mq1_h.threshold[++i]; - mq1_field->threshold1[index] = mq1_h.threshold[++i]; - mq1_field->threshold2[index] = mq1_h.threshold[++i]; - mq1_field->threshold3[index] = mq1_h.threshold[++i]; - mq1_field->threshold4[index] = mq1_h.threshold[++i]; - mq1_field->threshold5[index] = mq1_h.threshold[++i]; - mq1_field->threshold6[index] = mq1_h.threshold[++i]; - mq1_field->threshold7[index] = mq1_h.threshold[++i]; + mq1_field->threshold0[index] = mq1_h.threshold[0]; + mq1_field->threshold1[index] = mq1_h.threshold[1]; + mq1_field->threshold2[index] = mq1_h.threshold[2]; + mq1_field->threshold3[index] = mq1_h.threshold[3]; + mq1_field->threshold4[index] = mq1_h.threshold[4]; + mq1_field->threshold5[index] = mq1_h.threshold[5]; + mq1_field->threshold6[index] = mq1_h.threshold[6]; + mq1_field->threshold7[index] = mq1_h.threshold[7]; /*header_extension_id is char[5]*/ snprintf(mq1_field->header_extension_id + index * MQ1_CHAR_LEN_HEADER_EXTENSION_ID, @@ -328,15 +327,14 @@ void fill_MQ1_quad_fields(MQ1_fields *mq1_field, unsigned int index, mq1q mq1_h) mq1_field->colour_mode[index] = mq1_h.colour_mode; mq1_field->gain_mode[index] = mq1_h.gain_mode; /*threshold is float[8]*/ - unsigned int i = -1; - mq1_field->threshold0[index] = mq1_h.threshold[++i]; - mq1_field->threshold1[index] = mq1_h.threshold[++i]; - mq1_field->threshold2[index] = mq1_h.threshold[++i]; - mq1_field->threshold3[index] = mq1_h.threshold[++i]; - mq1_field->threshold4[index] = mq1_h.threshold[++i]; - mq1_field->threshold5[index] = mq1_h.threshold[++i]; - mq1_field->threshold6[index] = mq1_h.threshold[++i]; - mq1_field->threshold7[index] = mq1_h.threshold[++i]; + mq1_field->threshold0[index] = mq1_h.threshold[0]; + mq1_field->threshold1[index] = mq1_h.threshold[1]; + mq1_field->threshold2[index] = mq1_h.threshold[2]; + mq1_field->threshold3[index] = mq1_h.threshold[3]; + mq1_field->threshold4[index] = mq1_h.threshold[4]; + mq1_field->threshold5[index] = mq1_h.threshold[5]; + mq1_field->threshold6[index] = mq1_h.threshold[6]; + mq1_field->threshold7[index] = mq1_h.threshold[7]; /*header_extension_id is char[5]*/ snprintf(mq1_field->header_extension_id + index * MQ1_CHAR_LEN_HEADER_EXTENSION_ID, From 20481a013a417b407f9da43fec0f3d8dde26c98a Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 09:35:29 +0100 Subject: [PATCH 172/251] remove wrong comments --- src/compress.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compress.c b/src/compress.c index a17051d..be790c5 100644 --- a/src/compress.c +++ b/src/compress.c @@ -48,11 +48,11 @@ hid_t dcpl_compress(size_t dim, return H5I_INVALID_HID; } cd_values[0] = 0; - cd_values[1] = 0; // compression_level; - cd_values[2] = 0; // shuffle; - cd_values[3] = 0; // blocksize - cd_values[4] = compression_level; // unused - cd_values[5] = shuffle; // unused + cd_values[1] = 0; // unused; + cd_values[2] = 0; // unused; + cd_values[3] = 0; // blocksize + cd_values[4] = compression_level; + cd_values[5] = shuffle; cd_values[6] = blosc_compname_to_compcode(compressor); if (H5Pset_filter(dcpl, FILTER_BLOSC, H5Z_FLAG_OPTIONAL, 7, cd_values) < 0) { From 98a63fd85a70c3c656bb9aafb3fbb8453d57e894 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 09:39:52 +0100 Subject: [PATCH 173/251] Fix freeing and closing property lists and variables --- src/compress.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compress.c b/src/compress.c index be790c5..a8b62a9 100644 --- a/src/compress.c +++ b/src/compress.c @@ -37,19 +37,17 @@ hid_t dcpl_compress(size_t dim, char *version = (char *) malloc(sizeof(char) * 512); if (version == NULL) { fprintf(stderr, "malloc for version failed\n"); - free(version); return H5I_INVALID_HID; } char *date = (char *) malloc(sizeof(char) * 512); if (date == NULL) { fprintf(stderr, "malloc for date failed\n"); free(version); - free(date); return H5I_INVALID_HID; } cd_values[0] = 0; - cd_values[1] = 0; // unused; - cd_values[2] = 0; // unused; + cd_values[1] = 0; // unused + cd_values[2] = 0; // unused cd_values[3] = 0; // blocksize cd_values[4] = compression_level; cd_values[5] = shuffle; @@ -57,10 +55,12 @@ hid_t dcpl_compress(size_t dim, if (H5Pset_filter(dcpl, FILTER_BLOSC, H5Z_FLAG_OPTIONAL, 7, cd_values) < 0) { fprintf(stderr, "Error in H5Pset_filter\n"); + H5Pclose(dcpl); return H5I_INVALID_HID; } if (register_blosc(&version, &date) < 0) { fprintf(stderr, "Error in register_blosc\n"); + H5Pclose(dcpl); free(version); free(date); return H5I_INVALID_HID; From 65fc237ce14fbf712dc6ef65a5a0b0e54977f775 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 09:57:01 +0100 Subject: [PATCH 174/251] Modify logics to prevent freeing fb->data first --- src/compress.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/compress.c b/src/compress.c index a8b62a9..e2b7b3c 100644 --- a/src/compress.c +++ b/src/compress.c @@ -97,9 +97,9 @@ int compress_frame(framebuffer *fb, return -1; } - cbytes = blosc_compress_ctx(compression_level, shuffle, bufsize, nbytes, - fb->data, dest, destsize, compressor, blocksize, - numinternalthreads); + int cbytes = blosc_compress_ctx(compression_level, shuffle, bufsize, nbytes, + fb->data, dest, destsize, compressor, + blocksize, numinternalthreads); if (cbytes < 0) { fprintf(stderr, "Error in blosc_compress\n"); @@ -110,23 +110,20 @@ int compress_frame(framebuffer *fb, fprintf(stderr, "Blosc returned 0 bytes (uncompressible?). Forcing " "fallback to uncompressed write.\n"); cbytes = nbytes; + free(dest); return cbytes; } - // for showing compression ratio in each frame, profiling purposes - // if (cbytes != 0) { - // printf("compression: %ld -> %d (%.1fx)\n", nbytes, cbytes, (1. * nbytes) / - // cbytes); - //} - free(fb->data); - fb->data = malloc(destsize); - if (!fb->data) { - fprintf(stderr, "Error in malloc for fb->data\n"); + void *temp = realloc(fb->data, destsize); + if (temp) { + fb->data = temp; + memcpy(fb->data, dest, cbytes); + } else { + fprintf(stderr, + "Error in realloc for fb->data, fall back on the original data\n"); free(dest); - return -1; + return nbytes; } - - memcpy(fb->data, dest, cbytes); free(dest); return cbytes; #else From a02319f8c6bb5b43d8e4c15fc59f2493ea781cab Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 10:01:01 +0100 Subject: [PATCH 175/251] Change compatiable version check to 2.64 as AS_VAR_SET requires 2.64 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 6905505..5dadf5b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_PREREQ([2.69]) +AC_PREREQ([2.64]) AC_INIT([mib2h5], [0.0.1], [https://github.com/ePSIC-DLS/mib2h5/issues], [mib2h5], [https://github.com/ePSIC-DLS/mib2h5]) AM_INIT_AUTOMAKE([-Wall foreign -Werror tar-pax dist-xz]) AC_USE_SYSTEM_EXTENSIONS From 7f3ecd065c8a724fa089363027e9853b317e5eaf Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 10:03:17 +0100 Subject: [PATCH 176/251] Remove AC_CANONICAL_HOST --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5dadf5b..29e34ff 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,6 @@ AC_USE_SYSTEM_EXTENSIONS m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS([config.h]) -AC_CANONICAL_HOST AC_PROG_CC # --- Build Type Options -- From 2734b01b4d5bd92907120d889380e8f4165568a3 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 10:04:22 +0100 Subject: [PATCH 177/251] Fix rpath= --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 29e34ff..a262d73 100644 --- a/configure.ac +++ b/configure.ac @@ -146,7 +146,7 @@ AS_IF([test "x$enable_compression" != xno], [ AC_CHECK_HEADER([blosc.h], [ AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes], [ AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$BLOSCDIR/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSC_LIBDIR||g; s|-Wl,-rpath=$BLOSC_LIBDIR||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSC_LIBDIR||g; s|-Wl,-rpath,$BLOSC_LIBDIR||g"`]) AC_MSG_NOTICE([libblosc not found in $BLOSC_LIBDIR]) BLOSC_OK=no $as_unset ac_cv_lib_blosc_blosc_init @@ -154,7 +154,7 @@ AS_IF([test "x$enable_compression" != xno], [ ]) ], [ AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$BLOSCDIR/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSC_LIBDIR||g; s|-Wl,-rpath=$BLOSC_LIBDIR||g"`]) + AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSC_LIBDIR||g; s|-Wl,-rpath,$BLOSC_LIBDIR||g"`]) AC_MSG_NOTICE([blosc.h not found in $BLOSCDIR/include]) BLOSC_OK=no $as_unset ac_cv_header_blosc_h From 7863be75fa985870b0869d3d6fcb67de918c0234 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 10:08:13 +0100 Subject: [PATCH 178/251] Fix checking cache --- configure.ac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a262d73..2ae0cb3 100644 --- a/configure.ac +++ b/configure.ac @@ -150,7 +150,7 @@ AS_IF([test "x$enable_compression" != xno], [ AC_MSG_NOTICE([libblosc not found in $BLOSC_LIBDIR]) BLOSC_OK=no $as_unset ac_cv_lib_blosc_blosc_init - $as_unset_ac_cv_header_blosc_h + $as_unset ac_cv_header_blosc_h ]) ], [ AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$BLOSCDIR/include||g"`]) @@ -178,6 +178,7 @@ AS_IF([test "x$enable_compression" != xno], [ AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/build||g; s|-Wl,-rpath,$HBDIR/build||g"`]) AC_MSG_NOTICE([libblosc_filter not found in $HBDIR/build]) HDF5_BLOSC_OK=no + $as_unset ac_cv_lib_blosc_filter_register_blosc $as_unset ac_cv_header_blosc_filter_h ]) ], [ From 61f824900b924dfe6c569d178ca0fda195638042 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 10:42:21 +0100 Subject: [PATCH 179/251] Use m4macro to unset cache --- configure.ac | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 2ae0cb3..1ea7f96 100644 --- a/configure.ac +++ b/configure.ac @@ -38,19 +38,18 @@ AS_IF([test -n "$HDFDIR"], [ AC_MSG_NOTICE([libhdf5 not found on HDFDIR]) AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HDFDIR/include||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$HDFDIR/lib||g"`]) - $as_unset ac_cv_header_hdf5_h HDF5_OK=no ]) ], [ AC_MSG_NOTICE([hdf5.h not found on HDFDIR]) AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HDFDIR/include||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$HDFDIR/lib||g"`]) - $as_unset ac_cv_header_hdf5_h HDF5_OK=no ]) ]) AS_IF([test "x$HDF5_OK" != xyes], [ + AS_UNSET([ac_cv_header_hdf5_h]) AC_MSG_NOTICE([Trying system-wide HDF5 installation]) AC_CHECK_HEADER([hdf5.h], [ AC_CHECK_LIB([hdf5], [H5open], [ @@ -60,12 +59,10 @@ AS_IF([test "x$HDF5_OK" != xyes], [ ], [ AC_MSG_NOTICE([libhdf5 not found system-wide]) HDF5_OK=no - $as_unset ac_cv_header_hdf5_h ]) ], [ AC_MSG_NOTICE([hdf5.h not found system-wide]) HDF5_OK=no - $as_unset ac_cv_header_hdf5_h ]) ]) @@ -74,6 +71,7 @@ if test "x$HDF5_OK" != xyes; then for var in HDF5_ROOT HDF5_HOME HDF5_DIR; do eval dir=\$$var if test -n "$dir"; then + AS_UNSET([ac_cv_header_hdf5_h]) AC_MSG_NOTICE([Trying $var at $dir]) CPPFLAGS="$CPPFLAGS -I$dir/include" LDFLAGS="$LDFLAGS -L$dir/lib -Wl,-rpath,$dir/lib" @@ -87,13 +85,11 @@ if test "x$HDF5_OK" != xyes; then AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$dir/include||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath,$dir/lib||g"`]) HDF5_OK=no - $as_unset ac_cv_header_hdf5_h ]) ], [ AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$dir/include||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath,$dir/lib||g"`]) HDF5_OK=no - $as_unset ac_cv_header_hdf5_h ]) test "x$HDF5_OK" = xyes && break fi @@ -149,19 +145,18 @@ AS_IF([test "x$enable_compression" != xno], [ AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSC_LIBDIR||g; s|-Wl,-rpath,$BLOSC_LIBDIR||g"`]) AC_MSG_NOTICE([libblosc not found in $BLOSC_LIBDIR]) BLOSC_OK=no - $as_unset ac_cv_lib_blosc_blosc_init - $as_unset ac_cv_header_blosc_h ]) ], [ AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$BLOSCDIR/include||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$BLOSC_LIBDIR||g; s|-Wl,-rpath,$BLOSC_LIBDIR||g"`]) AC_MSG_NOTICE([blosc.h not found in $BLOSCDIR/include]) BLOSC_OK=no - $as_unset ac_cv_header_blosc_h ]) AS_IF([test "x$BLOSC_OK" != xyes], [ + AS_UNSET([ac_cv_lib_blosc_blosc_init]) + AS_UNSET([ac_cv_header_blosc_h]) AC_MSG_NOTICE([Falling back on system path for blosc]) AC_CHECK_HEADER([blosc.h], [ AC_CHECK_LIB([blosc], [blosc_init], [BLOSC_OK=yes], [BLOSC_OK=no]) @@ -178,19 +173,18 @@ AS_IF([test "x$enable_compression" != xno], [ AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/build||g; s|-Wl,-rpath,$HBDIR/build||g"`]) AC_MSG_NOTICE([libblosc_filter not found in $HBDIR/build]) HDF5_BLOSC_OK=no - $as_unset ac_cv_lib_blosc_filter_register_blosc - $as_unset ac_cv_header_blosc_filter_h ]) ], [ AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HBDIR/src||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-$HBDIR/build||g; s|-Wl,-rpath,$HBDIR/build||g"`]) AC_MSG_NOTICE([blosc_filter.h not found in $HBDIR/src]) HDF5_BLOSC_OK=no - $as_unset ac_cv_header_blosc_filter_h ]) ]) AS_IF([test "x$HDF5_BLOSC_OK" != xyes], [ + AS_UNSET([ac_cv_lib_blosc_filter_register_blosc]) + AS_UNSET([ac_cv_header_blosc_filter_h]) AC_MSG_NOTICE([Falling back on system path for hdf5-blosc]) AC_CHECK_HEADER([blosc_filter.h], [ AC_CHECK_LIB([blosc_filter], [register_blosc], [HDF5_BLOSC_OK=yes], [HDF5_BLOSC_OK=no]) From 34fbe4545e943f44582931921b285b6efb51be9b Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 10:46:05 +0100 Subject: [PATCH 180/251] Add comments for version --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 1ea7f96..8685105 100644 --- a/configure.ac +++ b/configure.ac @@ -1,3 +1,5 @@ +# 2.64 is needed for AS_VAR_SET +# check https://lists.gnu.org/archive/html/autotools-announce/2009-07/msg00000.html for detail AC_PREREQ([2.64]) AC_INIT([mib2h5], [0.0.1], [https://github.com/ePSIC-DLS/mib2h5/issues], [mib2h5], [https://github.com/ePSIC-DLS/mib2h5]) AM_INIT_AUTOMAKE([-Wall foreign -Werror tar-pax dist-xz]) From 152f562130afe947b1c0b9152411ae075b417099 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 10:48:24 +0100 Subject: [PATCH 181/251] Add in basic main.c for build purposes --- src/main.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/main.c diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..3491eef --- /dev/null +++ b/src/main.c @@ -0,0 +1,56 @@ +#include "config.h" +#include "mib_to_h5.h" +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int opt; + char *input_mib = NULL; + char *output_directory = "./"; + char *merlin_dset_name = "MerlinData"; + char *compressor = "blosclz"; + int compression_level = 9; + int shuffle = 2; + + while ((opt = getopt(argc, argv, "i:o:d:c:s:l:")) != -1) { + switch (opt) { + case 'i': + input_mib = optarg; + break; + case 'o': + output_directory = optarg; + break; + case 'd': + merlin_dset_name = optarg; + break; + case 'c': + compressor = optarg; + break; + case 's': + shuffle = atoi(optarg); + break; + case 'l': + compression_level = atoi(optarg); + break; + default: + fprintf( + stderr, + "Usage: -i input_mib -o output_directory -d merlin_dataset_name -c " + "compressor -s shuffle -l compression_level\n"); + return 1; + } + } + + if (input_mib == NULL) { + fprintf(stderr, "Error: input file must be specified\n"); + return 1; + } + + printf("%s\n", input_mib); + int status = mib_to_h5(input_mib, output_directory, merlin_dset_name, + compressor, shuffle, compression_level); + + return status; +} From 6ccbf74f00bdecd2c3e1641e7d3d6a8f254d1fec Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 11:12:57 +0100 Subject: [PATCH 182/251] Fix dangling dcpl in dcpl_compress --- src/compress.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/compress.c b/src/compress.c index e2b7b3c..4fa9cde 100644 --- a/src/compress.c +++ b/src/compress.c @@ -27,21 +27,25 @@ hid_t dcpl_compress(size_t dim, } else { if (H5Pset_chunk(dcpl, dim, frame_dim) < 0) { fprintf(stderr, "Error in H5Pset_chunk\n"); + H5Pclose(dcpl); return H5I_INVALID_HID; } if (H5Pset_fill_time(dcpl, H5D_FILL_TIME_NEVER) < 0) { fprintf(stderr, "Error in H5Pset_fill_time\n"); + H5Pclose(dcpl); return H5I_INVALID_HID; } #ifdef HAVE_COMPRESSION char *version = (char *) malloc(sizeof(char) * 512); if (version == NULL) { fprintf(stderr, "malloc for version failed\n"); + H5Pclose(dcpl); return H5I_INVALID_HID; } char *date = (char *) malloc(sizeof(char) * 512); if (date == NULL) { fprintf(stderr, "malloc for date failed\n"); + H5Pclose(dcpl); free(version); return H5I_INVALID_HID; } From 6397265bbf7bc28ce91a4d9945619579733b3fe0 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 11:34:08 +0100 Subject: [PATCH 183/251] Comment out mib_to_h5 --- src/main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index 3491eef..796b8fd 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,5 @@ #include "config.h" -#include "mib_to_h5.h" +// #include "mib_to_h5.h" #include #include #include @@ -49,8 +49,9 @@ int main(int argc, char *argv[]) } printf("%s\n", input_mib); - int status = mib_to_h5(input_mib, output_directory, merlin_dset_name, - compressor, shuffle, compression_level); + // int status = mib_to_h5(input_mib, output_directory, merlin_dset_name, + // compressor, shuffle, compression_level); - return status; + // return status; + return 0; } From c3eca7e7603e343df246991234859fa032412012 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 08:59:00 +0100 Subject: [PATCH 184/251] Add code for appending frames --- src/append.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/append.h | 20 ++++++ 2 files changed, 215 insertions(+) create mode 100644 src/append.c create mode 100644 src/append.h diff --git a/src/append.c b/src/append.c new file mode 100644 index 0000000..b579d52 --- /dev/null +++ b/src/append.c @@ -0,0 +1,195 @@ +#include "append.h" +#include "framebuffer.h" +#include "io_header.h" +#include "macros.h" + +#include +#include +#include + +void append_frame_to_dataset(hid_t dset, framebuffer *fb, int cbytes) +{ + if (!dset || !fb) { + fprintf(stderr, "Error in passing parameters in append_frame_to_dataset\n"); + return; + } + + unsigned int detx = *(fb->mq1_header->det_x); + unsigned int dety = *(fb->mq1_header->det_y); + int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + + (fb->mq1_header->pixel_depth[2] - '0'); + bufsize = bufsize / 8; + + if (cbytes == 0) { + cbytes = dety * detx * bufsize; + printf("cbytes == 0\n"); + } + + hid_t filespace = H5Dget_space(dset); + hsize_t dims[3]; + H5Sget_simple_extent_dims(filespace, dims, NULL); + + hsize_t frame_index = dims[0]; + + hsize_t new_dims[3] = {frame_index + 1, dety, detx}; + if (H5Dset_extent(dset, new_dims) < 0) { + fprintf(stderr, "Error in extending dataset in append_frame_to_dataset\n"); + return; + } + + hsize_t offset_chunk[3] = {frame_index, 0, 0}; + uint32_t filter_mask = 0; + + if (H5Dwrite_chunk(dset, H5P_DEFAULT, filter_mask, offset_chunk, cbytes, + fb->data) < 0) { + fprintf(stderr, "Failed in writing chunk\n"); + return; + } + + H5Sclose(filespace); +} + +void append_meta_to_dataset(hid_t *meta_handle, framebuffer *fb) +{ + if (meta_handle == NULL) { + fprintf(stderr, "meta_handle is NULL in append_meta_to_dataset\n"); + return; + } + if (fb == NULL) { + fprintf(stderr, "framebuffer is NULL in append_meta_to_dataset\n"); + return; + } + hid_t datatype, filespace, memspace; + info *mq1_iter = mq1_fields_info(fb->mq1_header); + + hsize_t dim[1]; + hsize_t frame_index; + hsize_t new_dim[1]; + hsize_t start[1]; + hsize_t count[1] = {1}; + hsize_t mem_dim[1] = {1}; + + for (size_t i = 0; i < MQ1_FIELDS_NUM_FIELDS; i++) { + datatype = H5Dget_type(meta_handle[i]); + filespace = H5Dget_space(meta_handle[i]); + H5Sget_simple_extent_dims(filespace, dim, NULL); + frame_index = dim[0]; + new_dim[0] = dim[0] + 1; + + if (H5Dset_extent(meta_handle[i], new_dim) < 0) { + fprintf(stderr, + "Error in extending dataset %s in append_meta_to_dataset\n", + mq1_iter[i].name); + H5Tclose(datatype); + H5Sclose(filespace); + return; + } + + H5Sclose(filespace); + filespace = H5Dget_space(meta_handle[i]); + start[0] = frame_index; + H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start, NULL, count, NULL); + + memspace = H5Screate_simple(1, mem_dim, NULL); + + if (H5Dwrite(meta_handle[i], datatype, memspace, filespace, H5P_DEFAULT, + mq1_iter[i].data) < 0) { + fprintf(stderr, "Error writing %s to metadata dataset\n", + mq1_iter[i].name); + } + + H5Sclose(memspace); + H5Sclose(filespace); + H5Tclose(datatype); + } +} + +void append_dac_to_dataset(unsigned int num_chips, + hid_t *dac_handle, + framebuffer *fb) +{ + hid_t datatype, filespace, memspace; + info *d_array[4]; + size_t ind = 0; + + if (!fb) { + fprintf(stderr, "Null framebuffer in append_dac_to_dataset\n"); + return; + } + + switch (num_chips) { + case 1: { + if (!fb->dac0) { + fprintf(stderr, "Null dac0 pointer in append_dac_to_dataset\n"); + return; + } else { + d_array[0] = dac_info(fb->dac0); + d_array[1] = NULL; + d_array[2] = NULL; + d_array[3] = NULL; + } + break; + } + case 4: { + if (!fb->dac0 || !fb->dac1 || !fb->dac2 || !fb->dac3) { + fprintf(stderr, "Null dac pointer detected in append_dac_to_dataset\n"); + return; + } else { + d_array[0] = dac_info(fb->dac0); + d_array[1] = dac_info(fb->dac1); + d_array[2] = dac_info(fb->dac2); + d_array[3] = dac_info(fb->dac3); + } + break; + } + default: { + fprintf(stderr, "Num_chips should be 1 or 4 in append_dac_to_dataset\n"); + return; + } + } + + hsize_t dim[1]; + hsize_t frame_index; + hsize_t new_dim[1]; + hsize_t start[1]; + hsize_t count[1] = {1}; + hsize_t mem_dim[1] = {1}; + + for (size_t i = 0; i < (size_t) num_chips; i++) { + for (size_t j = 0; j < DAC_NUM_FIELDS; j++) { + ind = i * DAC_NUM_FIELDS + j; + datatype = H5Dget_type(dac_handle[ind]); + filespace = H5Dget_space(dac_handle[ind]); + H5Sget_simple_extent_dims(filespace, dim, NULL); + frame_index = dim[0]; + new_dim[0] = dim[0] + 1; + + if (H5Dset_extent(dac_handle[ind], new_dim) < 0) { + fprintf(stderr, + "Error in extending dataset %s in append_dac_to_dataset\n", + d_array[i][j].name); + H5Tclose(datatype); + H5Sclose(filespace); + continue; + } + + H5Sclose(filespace); + filespace = H5Dget_space(dac_handle[ind]); + + start[0] = frame_index; + H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start, NULL, count, NULL); + + memspace = H5Screate_simple(1, mem_dim, NULL); + + if (H5Dwrite(dac_handle[ind], datatype, memspace, filespace, H5P_DEFAULT, + d_array[i][j].data) < 0) { + fprintf(stderr, "Error writing chip%ld, %s to metadata dac\n", i, + d_array[i][j].name); + return; + } + H5Sclose(memspace); + H5Sclose(filespace); + H5Tclose(datatype); + } + } +} diff --git a/src/append.h b/src/append.h new file mode 100644 index 0000000..891431f --- /dev/null +++ b/src/append.h @@ -0,0 +1,20 @@ +// clang-format Language: C +#ifndef APPEND_H +#define APPEND_H + +#include "framebuffer.h" +#include "io_header.h" +#include "parser.h" +#include "utils.h" +#include +#include + +void append_frame_to_dataset(hid_t dset, framebuffer *fb, int cbytes); + +void append_meta_to_dataset(hid_t *meta_handle, framebuffer *fb); + +void append_dac_to_dataset(unsigned int num_chips, + hid_t *dac_handle, + framebuffer *fb); + +#endif From e1d1ed978d244ee514db7e74c4647ef61c52612d Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 13:59:24 +0100 Subject: [PATCH 185/251] Add logics to handle error for get_space and get_simple_extent_dims --- src/append.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/append.c b/src/append.c index b579d52..6e4e30e 100644 --- a/src/append.c +++ b/src/append.c @@ -26,8 +26,18 @@ void append_frame_to_dataset(hid_t dset, framebuffer *fb, int cbytes) } hid_t filespace = H5Dget_space(dset); + if (filespace == H5I_INVALID_HID) { + fprintf(stderr, "Error in H5Dget_space in append_frame_to_dataset\n"); + return; + } hsize_t dims[3]; - H5Sget_simple_extent_dims(filespace, dims, NULL); + int rank = H5Sget_simple_extent_dims(filespace, dims, NULL); + if (rank < 0) { + fprintf(stderr, + "Error in H5Sget_simple_extent_dims in append_frame_to_dataset\n"); + H5Sclose(filespace); + return; + } hsize_t frame_index = dims[0]; From 9206004a3291d51b9df63aae14f3e7d6d9b48fc9 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 14:01:19 +0100 Subject: [PATCH 186/251] Add comments for clarifing the need to reopen filespace --- src/append.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/append.c b/src/append.c index 6e4e30e..6af7484 100644 --- a/src/append.c +++ b/src/append.c @@ -94,7 +94,7 @@ void append_meta_to_dataset(hid_t *meta_handle, framebuffer *fb) H5Sclose(filespace); return; } - + // update filespace as the dimension is extented H5Sclose(filespace); filespace = H5Dget_space(meta_handle[i]); start[0] = frame_index; From 1f08a9cd1a7a780e93cf5e0b7e7e2de9d190b478 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 14:20:51 +0100 Subject: [PATCH 187/251] Add comments for reopening filespace in appending dac --- src/append.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/append.c b/src/append.c index 6af7484..a6ff26a 100644 --- a/src/append.c +++ b/src/append.c @@ -183,6 +183,7 @@ void append_dac_to_dataset(unsigned int num_chips, continue; } + // Close and update the filespace as the dimension has extended H5Sclose(filespace); filespace = H5Dget_space(dac_handle[ind]); From be0f74e8d2399705d472d1f3586d7b752affa674 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 29 May 2025 14:30:37 +0100 Subject: [PATCH 188/251] Add a section in README about how to contribute and bug report --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 050e3ee..76fe1d0 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,12 @@ convert( For detailed parameter descriptions, refer to the header file `mib2h5.h` or the Python docstrings. +## Contributing + +Contribution is very welcomed. Please use the [issue +page](https://github.com/ePSIC-DLS/mib2h5/issues) to report any bug and missing +feature. + ## Licence MIT From 36b128c9f30289ab54ce4b21b97d28ce3521a37e Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 29 May 2025 14:35:14 +0100 Subject: [PATCH 189/251] Add a list of maintainers and contributors --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 76fe1d0..9c26767 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,16 @@ Contribution is very welcomed. Please use the [issue page](https://github.com/ePSIC-DLS/mib2h5/issues) to report any bug and missing feature. +### Maintainers + +- Timothy Poon (@ptim0626) + +### Contributors + +- Teo Ching (@teoching0705) +- Yousef Moazzam (@yousefmoazzam) +- Timothy Poon (@ptim0626) + ## Licence MIT From 1375e9e55c0bdf49f42614528ba0c177567c6ff2 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 14:48:34 +0100 Subject: [PATCH 190/251] Add in error handling logics --- src/append.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/src/append.c b/src/append.c index a6ff26a..f0deea5 100644 --- a/src/append.c +++ b/src/append.c @@ -78,11 +78,28 @@ void append_meta_to_dataset(hid_t *meta_handle, framebuffer *fb) hsize_t start[1]; hsize_t count[1] = {1}; hsize_t mem_dim[1] = {1}; + int rank = 0; + herr_t status; for (size_t i = 0; i < MQ1_FIELDS_NUM_FIELDS; i++) { - datatype = H5Dget_type(meta_handle[i]); + datatype = H5Dget_type(meta_handle[i]); + if (datatype < 0) { + fprintf(stderr, "Error in H5Dget_type in append_meta_to_dataset\n"); + return; + } filespace = H5Dget_space(meta_handle[i]); - H5Sget_simple_extent_dims(filespace, dim, NULL); + if (filespace == H5I_INVALID_HID) { + fprintf(stderr, "Error in H5Dget_space in append_meta_to_dataset\n"); + H5Tclose(datatype); + return; + } + rank = H5Sget_simple_extent_dims(filespace, dim, NULL); + if (rank < 0) { + fprintf(stderr, + "Error in H5Sget_simple_extent_dims in append_meta_to_dataset\n"); + H5Tclose(datatype); + return; + } frame_index = dim[0]; new_dim[0] = dim[0] + 1; @@ -97,10 +114,24 @@ void append_meta_to_dataset(hid_t *meta_handle, framebuffer *fb) // update filespace as the dimension is extented H5Sclose(filespace); filespace = H5Dget_space(meta_handle[i]); - start[0] = frame_index; - H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start, NULL, count, NULL); + if (filespace == H5I_INVALID_HID) { + fprintf(stderr, "Error in H5Dget_space in append_meta_to_dataset\n"); + return; + } + + start[0] = frame_index; + status = + H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start, NULL, count, NULL); + if (status < 0) { + fprintf(stderr, "Error H5Sselect_hyperslab in append_meta_to_dataset\n"); + return; + } memspace = H5Screate_simple(1, mem_dim, NULL); + if (memspace < 0) { + fprintf(stderr, "Error H5Screate_simple in append_meta_to_dataset\n"); + return; + } if (H5Dwrite(meta_handle[i], datatype, memspace, filespace, H5P_DEFAULT, mq1_iter[i].data) < 0) { @@ -164,13 +195,31 @@ void append_dac_to_dataset(unsigned int num_chips, hsize_t start[1]; hsize_t count[1] = {1}; hsize_t mem_dim[1] = {1}; + int rank = 0; + herr_t status; for (size_t i = 0; i < (size_t) num_chips; i++) { for (size_t j = 0; j < DAC_NUM_FIELDS; j++) { - ind = i * DAC_NUM_FIELDS + j; - datatype = H5Dget_type(dac_handle[ind]); + ind = i * DAC_NUM_FIELDS + j; + datatype = H5Dget_type(dac_handle[ind]); + if (datatype < 0) { + fprintf(stderr, "Error in H5Dget_type in append_meta_to_dataset\n"); + return; + } filespace = H5Dget_space(dac_handle[ind]); - H5Sget_simple_extent_dims(filespace, dim, NULL); + if (filespace == H5I_INVALID_HID) { + fprintf(stderr, "Error in H5Dget_space in append_meta_to_dataset\n"); + H5Tclose(datatype); + return; + } + rank = H5Sget_simple_extent_dims(filespace, dim, NULL); + if (rank < 0) { + fprintf( + stderr, + "Error in H5Sget_simple_extent_dims in append_meta_to_dataset\n"); + H5Tclose(datatype); + return; + } frame_index = dim[0]; new_dim[0] = dim[0] + 1; @@ -186,11 +235,25 @@ void append_dac_to_dataset(unsigned int num_chips, // Close and update the filespace as the dimension has extended H5Sclose(filespace); filespace = H5Dget_space(dac_handle[ind]); + if (filespace == H5I_INVALID_HID) { + fprintf(stderr, "Error in H5Dget_space in append_meta_to_dataset\n"); + H5Tclose(datatype); + return; + } start[0] = frame_index; - H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start, NULL, count, NULL); + status = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start, NULL, + count, NULL); + if (status < 0) { + fprintf(stderr, "Error H5Sselect_hyperslab in append_dac_to_dataset\n"); + return; + } memspace = H5Screate_simple(1, mem_dim, NULL); + if (memspace == H5I_INVALID_HID) { + fprintf(stderr, "Error H5Screate_simple in append_dac_to_dataset\n"); + return; + } if (H5Dwrite(dac_handle[ind], datatype, memspace, filespace, H5P_DEFAULT, d_array[i][j].data) < 0) { From 849795a3a6632e9d6a4d5d37f9e8927f1d40df3d Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Thu, 29 May 2025 16:07:48 +0100 Subject: [PATCH 191/251] add comments for clarifying the freeing of array used --- src/append.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/append.c b/src/append.c index f0deea5..033f029 100644 --- a/src/append.c +++ b/src/append.c @@ -61,6 +61,7 @@ void append_frame_to_dataset(hid_t dset, framebuffer *fb, int cbytes) void append_meta_to_dataset(hid_t *meta_handle, framebuffer *fb) { + // meta_handle and mq1_iter will be free outside this if (meta_handle == NULL) { fprintf(stderr, "meta_handle is NULL in append_meta_to_dataset\n"); return; @@ -149,6 +150,7 @@ void append_dac_to_dataset(unsigned int num_chips, hid_t *dac_handle, framebuffer *fb) { + // dac_handle and d_array will be freed outside this hid_t datatype, filespace, memspace; info *d_array[4]; size_t ind = 0; From 193a81685b8db99871c8335bba59edaeec8c0158 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 15:55:27 +0100 Subject: [PATCH 192/251] Add files for cython wrapper --- mib2h5_wrapper.pyx | 24 ++++++++++++++++++++++ setup.py | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 mib2h5_wrapper.pyx create mode 100644 setup.py diff --git a/mib2h5_wrapper.pyx b/mib2h5_wrapper.pyx new file mode 100644 index 0000000..7272f18 --- /dev/null +++ b/mib2h5_wrapper.pyx @@ -0,0 +1,24 @@ +# mib_wrapper.pyx + +cdef extern from "mib_to_h5.h": + int mib_to_h5(char *filename, + char *output_directory, + char *merlin_dset_name, + char *compressor, + unsigned int shuffle, + unsigned int compression_level) + +def py_mib_to_h5(str filename, + str output_directory, + str merlin_dset_name, + str compressor, + int shuffle, + int compression_level): + return mib_to_h5( + filename.encode('utf-8'), + output_directory.encode('utf-8'), + merlin_dset_name.encode('utf-8'), + compressor.encode('utf-8'), + shuffle, + compression_level + ) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..337c1e8 --- /dev/null +++ b/setup.py @@ -0,0 +1,51 @@ +# setup.py + +from setuptools import setup, Extension +from Cython.Build import cythonize +import os + +HDF5_ROOT = os.environ.get("HDF5_ROOT", "/usr") + +hdf5_include = os.path.join(HDF5_ROOT, "include") +hdf5_lib = os.path.join(HDF5_ROOT, "lib") + +BLOSC_ROOT = os.environ.get("BLOSC_ROOT", "/usr") + +blosc_include = os.path.join(BLOSC_ROOT, "include") +blosc_lib = os.path.join(BLOSC_ROOT, "lib64") + +HDF5_BLOSC_ROOT = os.environ.get("HDF5_BLOSC_ROOT", "/usr") + +hdf5_blosc_include = os.path.join(HDF5_BLOSC_ROOT, "src") +hdf5_blosc_lib = os.path.join(HDF5_BLOSC_ROOT, "build") + +ext = Extension( + name="mib2h5_wrapper", + sources=[ + "mib2h5_wrapper.pyx", + "src/mib_to_h5.c", + "src/append.c", + "src/compress.c", + "src/framebuffer.c", + "src/hdf5_init.c", + "src/hdf5_init_meta.c", + "src/io_header.c", + "src/parser.c", + "src/read.c", + "src/utils.c" + ], + include_dirs=["src", hdf5_include, ".", blosc_include, hdf5_blosc_include], + library_dirs=[hdf5_lib, blosc_lib, hdf5_blosc_lib], + libraries=["hdf5", "blosc", "blosc_filter"], + extra_compile_args=["-std=c11"], + extra_link_args=[ + f"-Wl,-rpath,{hdf5_lib}", + f"-Wl,-rpath,{blosc_lib}", + f"-Wl,-rpath,{hdf5_blosc_lib}" + ], +) + +setup( + name="mib2h5_wrapper", + ext_modules=cythonize(ext, language_level=3), +) From 7a78ea44fc29a88de7f8eebb8c3a9bacbb74b279 Mon Sep 17 00:00:00 2001 From: Sze Ching Date: Wed, 28 May 2025 16:24:23 +0100 Subject: [PATCH 193/251] Add checks for header file --- setup.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/setup.py b/setup.py index 337c1e8..601b853 100644 --- a/setup.py +++ b/setup.py @@ -3,22 +3,43 @@ from setuptools import setup, Extension from Cython.Build import cythonize import os +import sys + +def assert_file_exists(path, filename): + full_path = os.path.join(path, filename) + if not os.path.exists(full_path): + print(f"{filename} not found in {path}") + return False + else: + print(f"{filename} found in {path}") + return True + + HDF5_ROOT = os.environ.get("HDF5_ROOT", "/usr") hdf5_include = os.path.join(HDF5_ROOT, "include") hdf5_lib = os.path.join(HDF5_ROOT, "lib") +if not assert_file_exists(hdf5_include, "hdf5.h"): + sys.exit(1) + BLOSC_ROOT = os.environ.get("BLOSC_ROOT", "/usr") blosc_include = os.path.join(BLOSC_ROOT, "include") blosc_lib = os.path.join(BLOSC_ROOT, "lib64") +if not assert_file_exists(blosc_include, "blosc.h"): + sys.exit(1) + HDF5_BLOSC_ROOT = os.environ.get("HDF5_BLOSC_ROOT", "/usr") hdf5_blosc_include = os.path.join(HDF5_BLOSC_ROOT, "src") hdf5_blosc_lib = os.path.join(HDF5_BLOSC_ROOT, "build") +if not assert_file_exists(hdf5_blosc_include, "blosc_filter.h"): + sys.exit(1) + ext = Extension( name="mib2h5_wrapper", sources=[ From f8f929d7484d8336f5eb24a89c0caf5a6b788a9d Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Sat, 5 Jul 2025 21:49:37 +0100 Subject: [PATCH 194/251] Relocate Python wrapper files --- mib2h5_wrapper.pyx | 24 -------------- python/mib2h5.pyx | 81 ++++++++++++++++++++++++++++++++++++++++++++++ python/setup.py | 67 ++++++++++++++++++++++++++++++++++++++ setup.py | 72 ----------------------------------------- 4 files changed, 148 insertions(+), 96 deletions(-) delete mode 100644 mib2h5_wrapper.pyx create mode 100644 python/mib2h5.pyx create mode 100644 python/setup.py delete mode 100644 setup.py diff --git a/mib2h5_wrapper.pyx b/mib2h5_wrapper.pyx deleted file mode 100644 index 7272f18..0000000 --- a/mib2h5_wrapper.pyx +++ /dev/null @@ -1,24 +0,0 @@ -# mib_wrapper.pyx - -cdef extern from "mib_to_h5.h": - int mib_to_h5(char *filename, - char *output_directory, - char *merlin_dset_name, - char *compressor, - unsigned int shuffle, - unsigned int compression_level) - -def py_mib_to_h5(str filename, - str output_directory, - str merlin_dset_name, - str compressor, - int shuffle, - int compression_level): - return mib_to_h5( - filename.encode('utf-8'), - output_directory.encode('utf-8'), - merlin_dset_name.encode('utf-8'), - compressor.encode('utf-8'), - shuffle, - compression_level - ) diff --git a/python/mib2h5.pyx b/python/mib2h5.pyx new file mode 100644 index 0000000..7537ff1 --- /dev/null +++ b/python/mib2h5.pyx @@ -0,0 +1,81 @@ +# cython: language_level=3 + +cdef extern from "mib_to_h5.h": + int mib_to_h5(const char *filename, + const char *output_directory, + const char *merlin_dset_name, + const char *compressor, + unsigned int shuffle, + unsigned int compression_level) + +def convert(str filename, + str output_directory="./", + str merlin_dset_name="MerlinData", + str compressor="blosclz", + int shuffle=2, + int compression_level=9): + """ + Convert a MIB file to HDF5 format. + + Parameters + ---------- + filename : str + Path to the input MIB file + output_directory : str, optional + Directory where the output HDF5 file will be saved (default: "./") + merlin_dset_name : str, optional + Name of the dataset in the HDF5 file (default: "MerlinData") + compressor : str, optional + Compression algorithm to use (default: "blosclz") + shuffle : int, optional + Shuffle filter setting (default: 2) + compression_level : int, optional + Compression level 0-9 (default: 9) + + Returns + ------- + int + 0 on success, negative value on error + + Raises + ------ + ValueError + If required parameters are missing or invalid + RuntimeError + If the conversion fails + """ + if not filename: + raise ValueError("Input filename cannot be empty.") + + if not output_directory: + raise ValueError("Output directory cannot be empty.") + + if not merlin_dset_name: + raise ValueError("Dataset name cannot be empty.") + + if shuffle < 0 or shuffle > 2: + raise ValueError("Shuffle must be 0, 1, or 2.") + + if compression_level < 0 or compression_level > 9: + raise ValueError("Compression level must be between 0 and 9.") + + # encode strings to bytes + cdef bytes b_filename = filename.encode() + cdef bytes b_output_directory = output_directory.encode() + cdef bytes b_merlin_dset_name = merlin_dset_name.encode() + cdef bytes b_compressor = compressor.encode() if compressor else b"" + + # call the C function + cdef int result = mib_to_h5( + b_filename, + b_output_directory, + b_merlin_dset_name, + b_compressor, + shuffle, + compression_level + ) + + if result != 0: + raise RuntimeError(f"Conversion failed with error code: {result}") + + return result diff --git a/python/setup.py b/python/setup.py new file mode 100644 index 0000000..47359a2 --- /dev/null +++ b/python/setup.py @@ -0,0 +1,67 @@ +from setuptools import setup, Extension +from Cython.Build import cythonize +from pathlib import Path +import os + + +def check_header(include_dir, header_file): + header_path = Path(include_dir) / header_file + if not header_path.exists(): + raise FileNotFoundError(f"{header_file} not found in {include_dir}") + + +# hdf5 paths +HDF5_ROOT = os.environ.get("HDF5_ROOT", "/usr") +hdf5_include = Path(HDF5_ROOT) / "include" +hdf5_lib = Path(HDF5_ROOT) / "lib" +check_header(hdf5_include, "hdf5.h") + +# blosc paths +BLOSC_ROOT = os.environ.get("BLOSC_ROOT", "/usr") +blosc_include = Path(BLOSC_ROOT) / "include" +blosc_lib = Path(BLOSC_ROOT) / "lib64" +check_header(blosc_include, "blosc.h") + +# hdf5-blosc paths +HDF5_BLOSC_ROOT = os.environ.get("HDF5_BLOSC_ROOT", "/usr") +hdf5_blosc_include = Path(HDF5_BLOSC_ROOT) / "src" +hdf5_blosc_lib = Path(HDF5_BLOSC_ROOT) / "build" +check_header(hdf5_blosc_include, "blosc_filter.h") + +ext = Extension( + name="mib2h5", + sources=[ + "mib2h5.pyx", + "../src/mib_to_h5.c", + "../src/append.c", + "../src/compress.c", + "../src/framebuffer.c", + "../src/hdf5_init.c", + "../src/hdf5_init_meta.c", + "../src/io_header.c", + "../src/parser.c", + "../src/read.c", + "../src/utils.c" + ], + include_dirs=["../src", + str(hdf5_include), + str(blosc_include), + str(hdf5_blosc_include) + ], + library_dirs=[str(hdf5_lib), + str(blosc_lib), + str(hdf5_blosc_lib) + ], + libraries=["hdf5", "blosc", "blosc_filter"], + extra_compile_args=["-std=c11"], + extra_link_args=[ + f"-Wl,-rpath,{hdf5_lib}", + f"-Wl,-rpath,{blosc_lib}", + f"-Wl,-rpath,{hdf5_blosc_lib}" + ], +) + +setup( + name="mib2h5", + ext_modules=cythonize(ext, language_level=3), +) diff --git a/setup.py b/setup.py deleted file mode 100644 index 601b853..0000000 --- a/setup.py +++ /dev/null @@ -1,72 +0,0 @@ -# setup.py - -from setuptools import setup, Extension -from Cython.Build import cythonize -import os -import sys - -def assert_file_exists(path, filename): - full_path = os.path.join(path, filename) - if not os.path.exists(full_path): - print(f"{filename} not found in {path}") - return False - else: - print(f"{filename} found in {path}") - return True - - - -HDF5_ROOT = os.environ.get("HDF5_ROOT", "/usr") - -hdf5_include = os.path.join(HDF5_ROOT, "include") -hdf5_lib = os.path.join(HDF5_ROOT, "lib") - -if not assert_file_exists(hdf5_include, "hdf5.h"): - sys.exit(1) - -BLOSC_ROOT = os.environ.get("BLOSC_ROOT", "/usr") - -blosc_include = os.path.join(BLOSC_ROOT, "include") -blosc_lib = os.path.join(BLOSC_ROOT, "lib64") - -if not assert_file_exists(blosc_include, "blosc.h"): - sys.exit(1) - -HDF5_BLOSC_ROOT = os.environ.get("HDF5_BLOSC_ROOT", "/usr") - -hdf5_blosc_include = os.path.join(HDF5_BLOSC_ROOT, "src") -hdf5_blosc_lib = os.path.join(HDF5_BLOSC_ROOT, "build") - -if not assert_file_exists(hdf5_blosc_include, "blosc_filter.h"): - sys.exit(1) - -ext = Extension( - name="mib2h5_wrapper", - sources=[ - "mib2h5_wrapper.pyx", - "src/mib_to_h5.c", - "src/append.c", - "src/compress.c", - "src/framebuffer.c", - "src/hdf5_init.c", - "src/hdf5_init_meta.c", - "src/io_header.c", - "src/parser.c", - "src/read.c", - "src/utils.c" - ], - include_dirs=["src", hdf5_include, ".", blosc_include, hdf5_blosc_include], - library_dirs=[hdf5_lib, blosc_lib, hdf5_blosc_lib], - libraries=["hdf5", "blosc", "blosc_filter"], - extra_compile_args=["-std=c11"], - extra_link_args=[ - f"-Wl,-rpath,{hdf5_lib}", - f"-Wl,-rpath,{blosc_lib}", - f"-Wl,-rpath,{hdf5_blosc_lib}" - ], -) - -setup( - name="mib2h5_wrapper", - ext_modules=cythonize(ext, language_level=3), -) From 0473f72e3a0f7a5fd25b397b80791ed78f3b56b2 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Sun, 6 Jul 2025 12:28:46 +0100 Subject: [PATCH 195/251] Uncomment placeholder mib_to_h5 function --- src/main.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index 796b8fd..10947b5 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,5 @@ #include "config.h" -// #include "mib_to_h5.h" +#include "mib_to_h5.h" #include #include #include @@ -48,10 +48,8 @@ int main(int argc, char *argv[]) return 1; } - printf("%s\n", input_mib); - // int status = mib_to_h5(input_mib, output_directory, merlin_dset_name, - // compressor, shuffle, compression_level); + int status = mib_to_h5(input_mib, output_directory, merlin_dset_name, + compressor, shuffle, compression_level); - // return status; - return 0; + return status; } From eff4f6824bcfc80ea6ba5d69d9493289f04cd945 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Sun, 6 Jul 2025 12:30:45 +0100 Subject: [PATCH 196/251] Add mib_to_h5 to make target --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index b2eb71f..2ed4d69 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,5 +2,5 @@ bin_PROGRAMS = mib2h5 # Source files -mib2h5_SOURCES = main.c utils.c io_header.c parser.c framebuffer.c hdf5_init.c hdf5_init_meta.c read.c append.c +mib2h5_SOURCES = main.c mib_to_h5.c utils.c io_header.c parser.c framebuffer.c hdf5_init.c hdf5_init_meta.c read.c append.c compress.c mib2h5_LDADD = -lhdf5 @LIBCOMPRESSION@ From aff684c254f68511520e968c5bf0e0d2466c0847 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Sun, 6 Jul 2025 12:32:21 +0100 Subject: [PATCH 197/251] Add header file for the main conversion function --- src/mib_to_h5.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/mib_to_h5.h diff --git a/src/mib_to_h5.h b/src/mib_to_h5.h new file mode 100644 index 0000000..584a962 --- /dev/null +++ b/src/mib_to_h5.h @@ -0,0 +1,12 @@ +// clang-format Language: C +#ifndef MIB_TO_H5_H +#define MIB_TO_H5_H + +int mib_to_h5(const char *filename, + const char *output_directory, + const char *merlin_dset_name, + const char *compressor, + unsigned int shuffle, + unsigned int compression_level); + +#endif From 2f2295008d8acf6e79caa25aa71315a797a7fafd Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Mon, 7 Jul 2025 22:03:35 +0100 Subject: [PATCH 198/251] Fix typos in error message in allocate_frame_data --- src/framebuffer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index 1d8f1a2..f4e2e3c 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -73,7 +73,7 @@ void allocate_frame_data(framebuffer *fb) case 1: { data = malloc(sizeof(uint8_t) * detx * dety); if (!data) { - fprintf(stderr, "malloc failed for data in read_frame"); + fprintf(stderr, "malloc failed for data in allocate_frame_data\n"); return; } fb->data = data; @@ -85,7 +85,7 @@ void allocate_frame_data(framebuffer *fb) case 2: { data = malloc(sizeof(uint16_t) * detx * dety); if (!data) { - fprintf(stderr, "malloc failed for data in read_frame"); + fprintf(stderr, "malloc failed for data in allocate_frame_data\n"); return; } fb->data = data; @@ -97,7 +97,7 @@ void allocate_frame_data(framebuffer *fb) case 4: { data = malloc(sizeof(uint32_t) * detx * dety); if (!data) { - fprintf(stderr, "malloc failed for data in read_frame"); + fprintf(stderr, "malloc failed for data in allocate_frame_data\n"); return; } fb->data = data; @@ -109,7 +109,7 @@ void allocate_frame_data(framebuffer *fb) case 8: { data = malloc(sizeof(uint64_t) * detx * dety); if (!data) { - fprintf(stderr, "malloc failed for data in read_frame"); + fprintf(stderr, "malloc failed for data in allocate_frame_data\n"); return; } fb->data = data; From cdac546d371e53c898b2088346828135d86e4e22 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Mon, 7 Jul 2025 22:06:29 +0100 Subject: [PATCH 199/251] Fix memory free-up in error path --- src/framebuffer.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/framebuffer.c b/src/framebuffer.c index f4e2e3c..89c76f8 100644 --- a/src/framebuffer.c +++ b/src/framebuffer.c @@ -64,6 +64,8 @@ void allocate_frame_data(framebuffer *fb) void **buffer = malloc(sizeof(void *) * dety); if (!buffer) { fprintf(stderr, "Error in malloc for fb->rows in allocate_frame_data\n"); + fb->rows = NULL; + fb->data = NULL; return; } void *data = NULL; @@ -74,6 +76,9 @@ void allocate_frame_data(framebuffer *fb) data = malloc(sizeof(uint8_t) * detx * dety); if (!data) { fprintf(stderr, "malloc failed for data in allocate_frame_data\n"); + free(buffer); + fb->rows = NULL; + fb->data = NULL; return; } fb->data = data; @@ -86,6 +91,9 @@ void allocate_frame_data(framebuffer *fb) data = malloc(sizeof(uint16_t) * detx * dety); if (!data) { fprintf(stderr, "malloc failed for data in allocate_frame_data\n"); + free(buffer); + fb->rows = NULL; + fb->data = NULL; return; } fb->data = data; @@ -98,6 +106,9 @@ void allocate_frame_data(framebuffer *fb) data = malloc(sizeof(uint32_t) * detx * dety); if (!data) { fprintf(stderr, "malloc failed for data in allocate_frame_data\n"); + free(buffer); + fb->rows = NULL; + fb->data = NULL; return; } fb->data = data; @@ -110,6 +121,9 @@ void allocate_frame_data(framebuffer *fb) data = malloc(sizeof(uint64_t) * detx * dety); if (!data) { fprintf(stderr, "malloc failed for data in allocate_frame_data\n"); + free(buffer); + fb->rows = NULL; + fb->data = NULL; return; } fb->data = data; @@ -119,10 +133,10 @@ void allocate_frame_data(framebuffer *fb) break; } default: - printf("Unsupported pixel depth, single bit will be implemented later\n"); - if (data) - free(data); + fprintf(stderr, "Unsupported pixel depth in allocate_frame_data\n"); free(buffer); + fb->rows = NULL; + fb->data = NULL; return; } } From f790d2ac7485aa710869ac1cbb2542cdc2474aeb Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Mon, 7 Jul 2025 22:53:00 +0100 Subject: [PATCH 200/251] Create expandable initial dataset for Merlin frames --- src/hdf5_init.c | 29 ++++++++++++++++------------- src/hdf5_init.h | 4 +--- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index b27365f..dda6735 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -53,42 +53,45 @@ void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl) void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, - int dtype, - hid_t memspace, + hid_t dtype, hid_t dcpl, hid_t lcpl, - size_t dim, hsize_t *frame_dim) { - hid_t dapl = H5I_INVALID_HID; - hid_t datatype = H5I_INVALID_HID; + hid_t dapl = H5I_INVALID_HID; if ((dapl = H5Pcreate(H5P_DATASET_ACCESS)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating dapl_id\n"); goto cleanup; } else { - unsigned int y = frame_dim[1]; - unsigned int x = frame_dim[2]; + // frame_dim is 2D with det_y and det_x + unsigned int y = frame_dim[0]; + unsigned int x = frame_dim[1]; + size_t dtype_size = H5Tget_size(dtype); if (H5Pset_chunk_cache(dapl, PRIME_FOR_HASH, - NUM_CHUNKS_IN_CACHE * dtype * y * x, 1.0) < 0) { + NUM_CHUNKS_IN_CACHE * dtype_size * y * x, 1.0) < 0) { fprintf(stderr, "Error in H5Pset_chunk_cache\n"); goto cleanup; } } - datatype = bufsize_to_datatype(dtype); + // create 3D dataspace for the dataset (frames x height x width) + // frames start at 0 for expandable dataset + hsize_t dims[3] = {0, frame_dim[0], frame_dim[1]}; + hsize_t maxdims[3] = {H5S_UNLIMITED, frame_dim[0], frame_dim[1]}; + hid_t filespace = H5Screate_simple(3, dims, maxdims); - if ((*merlin_dataset_id = H5Dcreate2(file, merlin_dataset_name, datatype, - memspace, lcpl, dcpl, dapl)) == + if ((*merlin_dataset_id = H5Dcreate2(file, merlin_dataset_name, dtype, + filespace, lcpl, dcpl, dapl)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating merlin_dataset\n"); + H5Sclose(filespace); goto cleanup; } + H5Sclose(filespace); cleanup: - if (H5Iis_valid(dcpl)) - H5Pclose(dcpl); if (H5Iis_valid(dapl)) H5Pclose(dapl); } diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 6aff2c1..14ea2d8 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -15,11 +15,9 @@ void initialize_file(char *filename, hid_t *file_id, hid_t fapl, hid_t fcpl); void create_merlin_dataset(hid_t *merlin_dataset_id, hid_t file, char *merlin_dataset_name, - int dtype, - hid_t memspace, + hid_t dtype, hid_t dcpl, hid_t lcpl, - size_t dim, hsize_t *frame_dim); #endif From ccc55af83fb92781bf78c625b4fb3eff8a417013 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 9 Jul 2025 01:21:52 +0100 Subject: [PATCH 201/251] Fix memory leak (won't be freed outside) --- src/append.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/append.c b/src/append.c index 033f029..968483c 100644 --- a/src/append.c +++ b/src/append.c @@ -61,7 +61,7 @@ void append_frame_to_dataset(hid_t dset, framebuffer *fb, int cbytes) void append_meta_to_dataset(hid_t *meta_handle, framebuffer *fb) { - // meta_handle and mq1_iter will be free outside this + // meta_handle will be free outside this if (meta_handle == NULL) { fprintf(stderr, "meta_handle is NULL in append_meta_to_dataset\n"); return; @@ -144,13 +144,17 @@ void append_meta_to_dataset(hid_t *meta_handle, framebuffer *fb) H5Sclose(filespace); H5Tclose(datatype); } + + if (mq1_iter) { + free(mq1_iter); + } } void append_dac_to_dataset(unsigned int num_chips, hid_t *dac_handle, framebuffer *fb) { - // dac_handle and d_array will be freed outside this + // dac_handle will be freed outside this hid_t datatype, filespace, memspace; info *d_array[4]; size_t ind = 0; @@ -267,5 +271,9 @@ void append_dac_to_dataset(unsigned int num_chips, H5Sclose(filespace); H5Tclose(datatype); } + + if (d_array[i]) { + free(d_array[i]); + } } } From 592070bf609320c49ea1e2c27ae0a2a1e2d815a2 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 9 Jul 2025 01:26:21 +0100 Subject: [PATCH 202/251] Add an utility function to determine the output filename --- src/utils.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/utils.h | 2 ++ 2 files changed, 44 insertions(+) diff --git a/src/utils.c b/src/utils.c index 12f1043..2eeb342 100644 --- a/src/utils.c +++ b/src/utils.c @@ -3,6 +3,7 @@ #include #include #include +#include // for strcasecmp #include const char *only_file_name(const char *absolute_file_path) @@ -11,6 +12,47 @@ const char *only_file_name(const char *absolute_file_path) return (rslash != NULL) ? rslash + 1 : absolute_file_path; } +char *create_output_filename(const char *input_path, const char *output_dir) +{ + // get base filename from path + const char *base_name = only_file_name(input_path); + if (!base_name) { + return NULL; + } + + // check if filename ends with .mib (case-insensitive) + size_t base_len = strlen(base_name); + const char *dot_mib = NULL; + if (base_len > 4) { + // check for .mib or .MIB at the end + if (strcasecmp(base_name + base_len - 4, ".mib") == 0) { + dot_mib = base_name + base_len - 4; + } + } + + // calculate output filename length + size_t name_len = dot_mib ? (size_t) (dot_mib - base_name) : base_len; + // +1 for '/', +4 for '.h5\0' + size_t output_len = strlen(output_dir) + 1 + name_len + 4; + + char *output_file = malloc(output_len); + if (!output_file) { + return NULL; + } + + // build output filename + if (dot_mib) { + // copy basename without .mib, then append .h5 + snprintf(output_file, output_len, "%s/%.*s.h5", output_dir, (int) name_len, + base_name); + } else { + // no .mib extension, just append .h5 + sprintf(output_file, "%s/%s.h5", output_dir, base_name); + } + + return output_file; +} + unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride) { unsigned int num_hdr = 0; diff --git a/src/utils.h b/src/utils.h index 2da04f8..146cd2b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -45,6 +45,8 @@ static inline void *xmalloc_debug( const char *only_file_name(const char *absolute_file_path); +char *create_output_filename(const char *input_path, const char *output_dir); + unsigned int num_of_headers(FILE *mib_ptr, const unsigned int stride); void header_meta_from_first(FILE *mib_ptr, From b2c9500cc09989aae1fc750239079b7a83252cc9 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Sat, 12 Jul 2025 22:29:53 +0100 Subject: [PATCH 203/251] Add initial implementation of main conversion function mib_to_h5 --- src/mib_to_h5.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++++ src/read.c | 2 - 2 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 src/mib_to_h5.c diff --git a/src/mib_to_h5.c b/src/mib_to_h5.c new file mode 100644 index 0000000..84bcfe0 --- /dev/null +++ b/src/mib_to_h5.c @@ -0,0 +1,259 @@ +#include "mib_to_h5.h" +#include "append.h" +#include "compress.h" +#include "framebuffer.h" +#include "hdf5_init.h" +#include "hdf5_init_meta.h" +#include "macros.h" +#include "parser.h" +#include "read.h" +#include "utils.h" +#include +#include +#include +#include +#include +#include + +int mib_to_h5(const char *filename, + const char *output_directory, + const char *merlin_dset_name, + const char *compressor, + unsigned int shuffle, + unsigned int compression_level) +{ + FILE *mib_ptr = NULL; + char *output_file = NULL; + hid_t fapl_id = H5P_DEFAULT; + hid_t fcpl_id = H5P_DEFAULT; + hid_t lcpl_id = H5P_DEFAULT; + hid_t file_id = H5I_INVALID_HID; + hid_t dcpl = H5P_DEFAULT; + hid_t memspace = H5I_INVALID_HID; + hid_t dtype = H5I_INVALID_HID; + hid_t merlin_dataset_id = H5I_INVALID_HID; + hid_t meta_handle[MQ1_FIELDS_NUM_FIELDS] = {0}; + hid_t *dac_handle = NULL; + framebuffer fb = {0}; + int ret = -1; + + // validate inputs + if (!filename || !output_directory || !merlin_dset_name) { + fprintf(stderr, "Error: Missing required parameters\n"); + return -1; + } + + // open MIB file + mib_ptr = fopen(filename, "rb"); + if (!mib_ptr) { + fprintf(stderr, "Error: Cannot open input file %s\n", filename); + return -1; + } + + // get header metadata from first frame + char header_id[MQ1_CHAR_LEN_HEADER_ID] = {0}; + unsigned int header_bytes = 0, num_chips = 0, det_x = 0, det_y = 0; + char pixel_depth[MQ1_CHAR_LEN_PIXEL_DEPTH] = {0}; + + header_meta_from_first(mib_ptr, header_id, &header_bytes, &num_chips, &det_x, + &det_y, pixel_depth); + + // validate pixel_depth string length and format + if (strlen(pixel_depth) != 3 || pixel_depth[0] != 'U' || + pixel_depth[1] < '0' || pixel_depth[1] > '9' || pixel_depth[2] < '0' || + pixel_depth[2] > '9') { + fprintf(stderr, "Error: Invalid pixel depth format: %s\n", pixel_depth); + goto cleanup; + } + + // calculate size of pixel data type + int bufsize = (pixel_depth[1] - '0') * 10 + (pixel_depth[2] - '0'); + bufsize = bufsize / 8; + + // sanity check for detector dimensions + // (arbitrarily limit to max 4096x4096 currently) + if (det_x > 4096 || det_y > 4096) { + fprintf(stderr, + "Error: Detector dimensions exceed maximum (4096x4096): %ux%u\n", + det_x, det_y); + goto cleanup; + } + + // calculate frame size in bytes + size_t frame_size = det_x * det_y * bufsize; + + // calculate stride (header + frame data) + size_t stride_calc = header_bytes + frame_size; + + // check stride fits in unsigned int (just for sure for API compatibility) + if (stride_calc > UINT_MAX) { + fprintf(stderr, "Error: Stride too large for unsigned int\n"); + goto cleanup; + } + unsigned int stride = (unsigned int) stride_calc; + + unsigned int num_frames = num_of_headers(mib_ptr, stride); + + printf("Converting %s:\n", filename); + printf(" Header: %s, %u bytes\n", header_id, header_bytes); + printf(" Detector: %ux%u, %s depth, %u chip(s)\n", det_x, det_y, pixel_depth, + num_chips); + printf(" Frames: %u, stride: %u bytes\n", num_frames, stride); + + // create output filename + output_file = create_output_filename(filename, output_directory); + if (!output_file) { + fprintf(stderr, "Error: Cannot create output filename\n"); + goto cleanup; + } + + // initialise HDF5 property lists + initialize_plist(output_file, &fapl_id, &fcpl_id, &lcpl_id); + + // create HDF5 file + initialize_file(output_file, &file_id, fapl_id, fcpl_id); + if (file_id < 0) { + fprintf(stderr, "Error: Cannot create HDF5 file\n"); + goto cleanup; + } + + // create dataset creation property list with chunking + dcpl = H5Pcreate(H5P_DATASET_CREATE); + if (dcpl < 0) { + fprintf(stderr, "Error: Cannot create dataset property list\n"); + goto cleanup; + } + + hsize_t chunk_dims[3] = {1, det_y, det_x}; + if (H5Pset_chunk(dcpl, 3, chunk_dims) < 0) { + fprintf(stderr, "Error: Cannot set chunk dimensions\n"); + goto cleanup; + } + + // TODO: Compression functionality to be implemented in a future PR + // The compression parameters (compressor, shuffle, compression_level) are + // currently accepted but not used. The cbytes parameter is set to 0 to + // indicate no compression. + int cbytes = 0; + + // create data memspace + hsize_t frame_dim[2] = {det_y, det_x}; + memspace = H5Screate_simple(2, frame_dim, NULL); + if (memspace < 0) { + fprintf(stderr, "Error: Cannot create memory dataspace\n"); + goto cleanup; + } + + // determine datatype + dtype = bufsize_to_datatype(bufsize); + if (dtype < 0) { + fprintf(stderr, "Error: Invalid buffer size for datatype\n"); + goto cleanup; + } + + // create main dataset + create_merlin_dataset(&merlin_dataset_id, file_id, merlin_dset_name, dtype, + dcpl, lcpl_id, frame_dim); + if (merlin_dataset_id < 0) { + fprintf(stderr, "Error: Cannot create main dataset\n"); + goto cleanup; + } + + // create metadata datasets + create_meta_mq1_fields_dataset(file_id, lcpl_id, meta_handle); + + // create DAC datasets + size_t dac_size = sizeof(hid_t) * DAC_NUM_FIELDS * num_chips; + dac_handle = malloc(dac_size); + if (!dac_handle) { + fprintf(stderr, "Error: Cannot allocate memory for DAC handles\n"); + goto cleanup; + } + create_dac_dataset(num_chips, file_id, lcpl_id, dac_handle); + + // allocate framebuffer + allocate_frame_header(&fb); + + // read first header to get dimensions for frame data allocation + read_header(mib_ptr, 0, &fb); + allocate_frame_data(&fb); + + // check if allocation succeeded + if (!fb.data || !fb.rows) { + fprintf(stderr, "Error: Failed to allocate framebuffer\n"); + goto cleanup; + } + + // process all frames + for (unsigned int i = 0; i < num_frames; ++i) { + unsigned long offset = (unsigned long) i * stride; + + // read frame header and data + read_header(mib_ptr, offset, &fb); + read_frame(mib_ptr, offset + header_bytes, &fb); + + // append frame data to dataset + append_frame_to_dataset(merlin_dataset_id, &fb, cbytes); + + // append metadata + append_meta_to_dataset(meta_handle, &fb); + + // append DAC data + append_dac_to_dataset(num_chips, dac_handle, &fb); + + // progress indicator + if ((i + 1) % 100 == 0 || i == num_frames - 1) { + printf("\rProcessed %u/%u frames", i + 1, num_frames); + fflush(stdout); + } + } + printf("\n"); + + printf("Conversion complete: %s\n", output_file); + ret = 0; // success + +cleanup: + // cleanup framebuffer + if (fb.data || fb.rows) { + deallocate_frame(&fb); + } + + // close HDF5 handles + if (memspace >= 0) + H5Sclose(memspace); + if (merlin_dataset_id >= 0) + H5Dclose(merlin_dataset_id); + + for (int i = 0; i < MQ1_FIELDS_NUM_FIELDS; ++i) { + if (meta_handle[i] > 0 && H5Iis_valid(meta_handle[i])) { + H5Dclose(meta_handle[i]); + } + } + + if (dac_handle) { + for (unsigned int i = 0; i < DAC_NUM_FIELDS * num_chips; ++i) { + if (dac_handle[i] > 0 && H5Iis_valid(dac_handle[i])) { + H5Dclose(dac_handle[i]); + } + } + free(dac_handle); + } + + if (dcpl != H5P_DEFAULT && dcpl >= 0) + H5Pclose(dcpl); + if (fapl_id != H5P_DEFAULT && fapl_id >= 0) + H5Pclose(fapl_id); + if (fcpl_id != H5P_DEFAULT && fcpl_id >= 0) + H5Pclose(fcpl_id); + if (lcpl_id != H5P_DEFAULT && lcpl_id >= 0) + H5Pclose(lcpl_id); + if (file_id >= 0) + H5Fclose(file_id); + + if (mib_ptr) + fclose(mib_ptr); + if (output_file) + free(output_file); + + return ret; +} diff --git a/src/read.c b/src/read.c index 9956e1b..33529ad 100644 --- a/src/read.c +++ b/src/read.c @@ -135,8 +135,6 @@ void read_frame(FILE *mib_ptr, unsigned long offset, framebuffer *fb) } } - int headersize = *(fb->mq1_header->header_bytes); - int bufsize = (fb->mq1_header->pixel_depth[1] - '0') * 10 + (fb->mq1_header->pixel_depth[2] - '0'); bufsize = bufsize / 8; From 412df2a370bdfe52e4d89234b8c78c6407467d77 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Mon, 14 Jul 2025 22:15:44 +0100 Subject: [PATCH 204/251] Avoid double headersize offset when called from mib_to_h5 --- src/mib_to_h5.c | 2 +- src/read.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mib_to_h5.c b/src/mib_to_h5.c index 84bcfe0..de09fdc 100644 --- a/src/mib_to_h5.c +++ b/src/mib_to_h5.c @@ -190,7 +190,7 @@ int mib_to_h5(const char *filename, // read frame header and data read_header(mib_ptr, offset, &fb); - read_frame(mib_ptr, offset + header_bytes, &fb); + read_frame(mib_ptr, offset, &fb); // append frame data to dataset append_frame_to_dataset(merlin_dataset_id, &fb, cbytes); diff --git a/src/read.c b/src/read.c index 33529ad..55c3cd8 100644 --- a/src/read.c +++ b/src/read.c @@ -143,10 +143,11 @@ void read_frame(FILE *mib_ptr, unsigned long offset, framebuffer *fb) return; } - int detx = *(fb->mq1_header->det_x); - int dety = *(fb->mq1_header->det_y); + int detx = *(fb->mq1_header->det_x); + int dety = *(fb->mq1_header->det_y); + unsigned int header_bytes = *(fb->mq1_header->header_bytes); - if (fseek(mib_ptr, offset + headersize, SEEK_SET) != 0) { + if (fseek(mib_ptr, offset + header_bytes, SEEK_SET) != 0) { fprintf(stderr, "fseek error in read_frame\n"); return; } From 3892b612aad3914cd930c5c48d889181ea7d1506 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 27 Aug 2025 09:29:50 +0100 Subject: [PATCH 205/251] Use snprintf for safety --- src/utils.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/utils.c b/src/utils.c index 2eeb342..02e600e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,10 +1,14 @@ #include "utils.h" +#include #include #include #include #include // for strcasecmp +#include #include +#include +#include const char *only_file_name(const char *absolute_file_path) { @@ -47,7 +51,7 @@ char *create_output_filename(const char *input_path, const char *output_dir) base_name); } else { // no .mib extension, just append .h5 - sprintf(output_file, "%s/%s.h5", output_dir, base_name); + snprintf(output_file, output_len, "%s/%s.h5", output_dir, base_name); } return output_file; From ecd3c75eca080e5f8339518646f8a69da308fd5e Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 27 Aug 2025 09:30:52 +0100 Subject: [PATCH 206/251] Enhance error message in getting file system block size --- src/utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.c b/src/utils.c index 02e600e..b5544e9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -206,7 +206,8 @@ unsigned long get_filesystem_block_size(const char *path) } if (statvfs(path, &stat) != 0) { - fprintf(stderr, "statvfs failed\n"); + fprintf(stderr, "statvfs failed for '%s': %s (errno=%d)\n", path, + strerror(errno), errno); return 1; } From 7d7dcefd963399220a3cc4baab934c7f8387f627 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 27 Aug 2025 09:31:36 +0100 Subject: [PATCH 207/251] Add a function to check if a directory exists --- src/utils.c | 29 +++++++++++++++++++++++++++++ src/utils.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/src/utils.c b/src/utils.c index b5544e9..ec5fca9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -213,3 +213,32 @@ unsigned long get_filesystem_block_size(const char *path) return stat.f_bsize; } + +int directory_exists(const char *dir_path) +{ + // check for NULL or empty path + if (!dir_path || *dir_path == '\0') { + fprintf(stderr, "Error: Directory path is empty or NULL\n"); + return -1; + } + + // check if path exists and get its stats + struct stat dir_stat; + if (stat(dir_path, &dir_stat) != 0) { + if (errno == ENOENT) { + fprintf(stderr, "Error: Directory '%s' does not exist\n", dir_path); + } else { + fprintf(stderr, "Error: Cannot access directory '%s': %s (errno=%d)\n", + dir_path, strerror(errno), errno); + } + return -1; + } + + // verify it's actually a directory + if (!S_ISDIR(dir_stat.st_mode)) { + fprintf(stderr, "Error: '%s' exists but is not a directory\n", dir_path); + return -1; + } + + return 0; +} diff --git a/src/utils.h b/src/utils.h index 146cd2b..9751bcf 100644 --- a/src/utils.h +++ b/src/utils.h @@ -61,4 +61,6 @@ hid_t bufsize_to_datatype(int dtype); unsigned long get_filesystem_block_size(const char *path); +int directory_exists(const char *dir_path); + #endif From 80d5788a573e4dbb739fcabc588ee8e57c36623f Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 27 Aug 2025 09:33:22 +0100 Subject: [PATCH 208/251] Avoid passing output file name to statvfs as it hasn't been created yet --- src/hdf5_init.c | 4 ++-- src/hdf5_init.h | 2 +- src/mib_to_h5.c | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/hdf5_init.c b/src/hdf5_init.c index dda6735..024a157 100644 --- a/src/hdf5_init.c +++ b/src/hdf5_init.c @@ -5,7 +5,7 @@ #include #include -void initialize_plist(char *path, +void initialize_plist(char *output_dir, hid_t *fapl_id, hid_t *fcpl_id, hid_t *lcpl_id) @@ -14,7 +14,7 @@ void initialize_plist(char *path, fprintf(stderr, "Error in creating fcpl in create_file\n"); return; } - unsigned long f_blocksize = get_filesystem_block_size(path); + unsigned long f_blocksize = get_filesystem_block_size(output_dir); printf("block size of filesystem: %ld\n", f_blocksize); if ((*fapl_id = H5Pcreate(H5P_FILE_ACCESS)) == H5I_INVALID_HID) { fprintf(stderr, "Error in creating fapl in create_file\n"); diff --git a/src/hdf5_init.h b/src/hdf5_init.h index 14ea2d8..cb614ae 100644 --- a/src/hdf5_init.h +++ b/src/hdf5_init.h @@ -5,7 +5,7 @@ #ifndef HDF5_INIT_H #define HDF5_INIT_H -void initialize_plist(char *path, +void initialize_plist(char *output_dir, hid_t *fapl_id, hid_t *fcpl_id, hid_t *lcpl_id); diff --git a/src/mib_to_h5.c b/src/mib_to_h5.c index de09fdc..ab13719 100644 --- a/src/mib_to_h5.c +++ b/src/mib_to_h5.c @@ -107,8 +107,13 @@ int mib_to_h5(const char *filename, goto cleanup; } + // validate output directory exists + if (directory_exists(output_directory) != 0) { + goto cleanup; + } + // initialise HDF5 property lists - initialize_plist(output_file, &fapl_id, &fcpl_id, &lcpl_id); + initialize_plist(output_directory, &fapl_id, &fcpl_id, &lcpl_id); // create HDF5 file initialize_file(output_file, &file_id, fapl_id, fcpl_id); From 59bb75d5fd8b20cc9727ba5903b88c270da838d0 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 27 Aug 2025 15:08:48 +0100 Subject: [PATCH 209/251] Use a custom build_ext class to run autotool configuration if necessary --- python/mib2h5.pyx | 81 -------------- python/setup.py | 263 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 220 insertions(+), 124 deletions(-) delete mode 100644 python/mib2h5.pyx diff --git a/python/mib2h5.pyx b/python/mib2h5.pyx deleted file mode 100644 index 7537ff1..0000000 --- a/python/mib2h5.pyx +++ /dev/null @@ -1,81 +0,0 @@ -# cython: language_level=3 - -cdef extern from "mib_to_h5.h": - int mib_to_h5(const char *filename, - const char *output_directory, - const char *merlin_dset_name, - const char *compressor, - unsigned int shuffle, - unsigned int compression_level) - -def convert(str filename, - str output_directory="./", - str merlin_dset_name="MerlinData", - str compressor="blosclz", - int shuffle=2, - int compression_level=9): - """ - Convert a MIB file to HDF5 format. - - Parameters - ---------- - filename : str - Path to the input MIB file - output_directory : str, optional - Directory where the output HDF5 file will be saved (default: "./") - merlin_dset_name : str, optional - Name of the dataset in the HDF5 file (default: "MerlinData") - compressor : str, optional - Compression algorithm to use (default: "blosclz") - shuffle : int, optional - Shuffle filter setting (default: 2) - compression_level : int, optional - Compression level 0-9 (default: 9) - - Returns - ------- - int - 0 on success, negative value on error - - Raises - ------ - ValueError - If required parameters are missing or invalid - RuntimeError - If the conversion fails - """ - if not filename: - raise ValueError("Input filename cannot be empty.") - - if not output_directory: - raise ValueError("Output directory cannot be empty.") - - if not merlin_dset_name: - raise ValueError("Dataset name cannot be empty.") - - if shuffle < 0 or shuffle > 2: - raise ValueError("Shuffle must be 0, 1, or 2.") - - if compression_level < 0 or compression_level > 9: - raise ValueError("Compression level must be between 0 and 9.") - - # encode strings to bytes - cdef bytes b_filename = filename.encode() - cdef bytes b_output_directory = output_directory.encode() - cdef bytes b_merlin_dset_name = merlin_dset_name.encode() - cdef bytes b_compressor = compressor.encode() if compressor else b"" - - # call the C function - cdef int result = mib_to_h5( - b_filename, - b_output_directory, - b_merlin_dset_name, - b_compressor, - shuffle, - compression_level - ) - - if result != 0: - raise RuntimeError(f"Conversion failed with error code: {result}") - - return result diff --git a/python/setup.py b/python/setup.py index 47359a2..616ba66 100644 --- a/python/setup.py +++ b/python/setup.py @@ -1,37 +1,219 @@ from setuptools import setup, Extension +from setuptools.command.build_ext import build_ext from Cython.Build import cythonize from pathlib import Path import os +import subprocess +from subprocess import CalledProcessError -def check_header(include_dir, header_file): - header_path = Path(include_dir) / header_file - if not header_path.exists(): - raise FileNotFoundError(f"{header_file} not found in {include_dir}") +class AutotoolsError(Exception): + """Exception raised when autotools configuration fails.""" + pass -# hdf5 paths -HDF5_ROOT = os.environ.get("HDF5_ROOT", "/usr") -hdf5_include = Path(HDF5_ROOT) / "include" -hdf5_lib = Path(HDF5_ROOT) / "lib" -check_header(hdf5_include, "hdf5.h") +class ConfigureBuildExt(build_ext): + """Custom build_ext that runs configure if needed.""" -# blosc paths -BLOSC_ROOT = os.environ.get("BLOSC_ROOT", "/usr") -blosc_include = Path(BLOSC_ROOT) / "include" -blosc_lib = Path(BLOSC_ROOT) / "lib64" -check_header(blosc_include, "blosc.h") + def run(self): + """Run build extension with autotools configuration if needed.""" + config_h_path = self.parent_dir / "config.h" -# hdf5-blosc paths -HDF5_BLOSC_ROOT = os.environ.get("HDF5_BLOSC_ROOT", "/usr") -hdf5_blosc_include = Path(HDF5_BLOSC_ROOT) / "src" -hdf5_blosc_lib = Path(HDF5_BLOSC_ROOT) / "build" -check_header(hdf5_blosc_include, "blosc_filter.h") + if not config_h_path.exists(): + print("config.h not found. Running autotools configuration...") + print("This is only needed once for the initial setup.") + self._run_autotools() -ext = Extension( - name="mib2h5", - sources=[ - "mib2h5.pyx", + super().run() + + def _run_autotools(self): + """Run autotools to generate config.h.""" + configure_path = self.parent_dir / "configure" + + if not configure_path.exists(): + self._run_autoreconf() + + self._run_configure() + print("Configuration completed.") + + def _run_autoreconf(self): + """Run autoreconf to generate configure script.""" + print("Running autoreconf -i...") + try: + subprocess.run( + ["autoreconf", "-i"], + cwd=self.parent_dir, + capture_output=True, + text=True, + check=True, + ) + except CalledProcessError as err: + raise AutotoolsError( + f"Failed to run autoreconf: {err.stderr}" + ) from err + + def _run_configure(self): + """Run configure script.""" + print("Running ./configure...") + configure_args = self._get_configure_args() + + try: + subprocess.run( + configure_args, + cwd=self.parent_dir, + capture_output=True, + text=True, + env=os.environ.copy(), + check=True, + ) + except CalledProcessError as err: + raise AutotoolsError( + "Configure failed. This is usually because of missing HDF5 " + f"libraries: {err.stderr}" + ) from err + + def _get_configure_args(self): + """Get configure command arguments.""" + hdf5_root = os.environ.get("HDF5_ROOT") + if hdf5_root: + hdf5_path = Path(hdf5_root).resolve() + if not hdf5_path.exists(): + msg = f"HDF5_ROOT path does not exist: {hdf5_path}" + raise AutotoolsError(msg) + return ["./configure", f"--with-hdf5={hdf5_path}"] + return ["./configure"] + + @property + def parent_dir(self): + return Path(__file__).parent.parent + + +def _check_header_exists(include_dir, header_file): + """Check if a header file exists in the given directory.""" + header_path = Path(include_dir) / header_file + return header_path.exists() and header_path.is_file() + + +def _get_library_path(root_path, lib_name="lib"): + """Get library path, checking lib64 first, then lib.""" + lib64_path = root_path / "lib64" + lib_path = root_path / lib_name + + if lib64_path.exists(): + return lib64_path + elif lib_path.exists(): + return lib_path + else: + raise FileNotFoundError(f"No library directory found in {root_path}") + + +def _find_hdf5_paths(): + """Find HDF5 include and library paths.""" + hdf5_root_env = os.environ.get("HDF5_ROOT") + + if hdf5_root_env: + hdf5_root = Path(hdf5_root_env).resolve() + else: + # try default paths + for default_path in ("/usr", "/usr/local"): + candidate = Path(default_path) + if _check_header_exists(candidate / "include", "hdf5.h"): + hdf5_root = candidate + break + else: + msg = ("HDF5 not found in default locations. Please set HDF5_ROOT " + "environment variable to your HDF5 installation.") + raise FileNotFoundError(msg) + + hdf5_include = hdf5_root / "include" + hdf5_lib = _get_library_path(hdf5_root) + + # verify hdf5 header exists + if not _check_header_exists(hdf5_include, "hdf5.h"): + msg = (f"HDF5 header not found at '{hdf5_include}'. Please verify your " + "HDF5 installation.") + raise FileNotFoundError(msg) + + return hdf5_include, hdf5_lib + + +def _check_compression_support(): + """Check for optional compression libraries.""" + blosc_root_env = os.environ.get("BLOSC_ROOT") + hdf5_blosc_root_env = os.environ.get("HDF5_BLOSC_ROOT") + + if not (blosc_root_env and hdf5_blosc_root_env): + return None + + try: + blosc_root = Path(blosc_root_env).resolve() + hdf5_blosc_root = Path(hdf5_blosc_root_env).resolve() + + blosc_include = blosc_root / "include" + blosc_lib = _get_library_path(blosc_root) + + hdf5_blosc_include = hdf5_blosc_root / "src" + hdf5_blosc_lib = hdf5_blosc_root / "build" + + # verify headers exist + if (_check_header_exists(blosc_include, "blosc.h") and + _check_header_exists(hdf5_blosc_include, "blosc_filter.h")): + return { + "include": blosc_include, + "lib": blosc_lib, + "hdf5_blosc_include": hdf5_blosc_include, + "hdf5_blosc_lib": hdf5_blosc_lib, + } + except FileNotFoundError: + pass + + return None + + +def _build_extension_config(): + """Build extension configuration.""" + # find hdf5 paths + hdf5_include, hdf5_lib = _find_hdf5_paths() + + # base configuration + include_dirs = ["..", "../src", hdf5_include] + library_dirs = [hdf5_lib] + libraries = ["hdf5"] + extra_link_args = [f"-Wl,-rpath,{hdf5_lib}"] + extra_compile_args = ["-std=c11"] + + # check for compression support + compression_config = _check_compression_support() + if compression_config: + include_dirs.extend([ + compression_config["include"], + compression_config["hdf5_blosc_include"], + ]) + library_dirs.extend([ + compression_config["lib"], + compression_config["hdf5_blosc_lib"], + ]) + libraries.extend(["blosc", "blosc_filter"]) + extra_link_args.extend([ + f"-Wl,-rpath,{compression_config['lib']}", + f"-Wl,-rpath,{compression_config['hdf5_blosc_lib']}", + ]) + extra_compile_args.append("-DENABLE_COMPRESSION") + print("Compression support enabled.") + else: + print("Compression support disabled (blosc libraries not found).") + + return { + "include_dirs": [str(path) for path in include_dirs], + "library_dirs": [str(path) for path in library_dirs], + "libraries": libraries, + "extra_compile_args": extra_compile_args, + "extra_link_args": extra_link_args, + } + +# source files for the extension +SOURCE_FILES = [ + "src/mib2h5/_wrapper.pyx", "../src/mib_to_h5.c", "../src/append.c", "../src/compress.c", @@ -41,27 +223,22 @@ def check_header(include_dir, header_file): "../src/io_header.c", "../src/parser.c", "../src/read.c", - "../src/utils.c" - ], - include_dirs=["../src", - str(hdf5_include), - str(blosc_include), - str(hdf5_blosc_include) - ], - library_dirs=[str(hdf5_lib), - str(blosc_lib), - str(hdf5_blosc_lib) - ], - libraries=["hdf5", "blosc", "blosc_filter"], - extra_compile_args=["-std=c11"], - extra_link_args=[ - f"-Wl,-rpath,{hdf5_lib}", - f"-Wl,-rpath,{blosc_lib}", - f"-Wl,-rpath,{hdf5_blosc_lib}" - ], + "../src/utils.c", +] + +config = _build_extension_config() + +ext = Extension( + name="mib2h5._wrapper", + sources=SOURCE_FILES, + **config, ) setup( - name="mib2h5", - ext_modules=cythonize(ext, language_level=3), + name="mib2h5", + packages=["mib2h5"], + package_dir={"": "src"}, + ext_modules=cythonize(ext, language_level=3), + python_requires=">=3.10", + cmdclass={"build_ext": ConfigureBuildExt}, ) From 110223e3f37649be0043ecd5b7ec4e6620a674e7 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 27 Aug 2025 15:11:41 +0100 Subject: [PATCH 210/251] Use a Cython wrapper script to call mib_to_h5 --- python/pyproject.toml | 58 ++++++++++++++++++++++++ python/setup.py | 13 +++--- python/src/mib2h5/__init__.py | 9 ++++ python/src/mib2h5/_wrapper.pyx | 81 ++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 python/pyproject.toml create mode 100644 python/src/mib2h5/__init__.py create mode 100644 python/src/mib2h5/_wrapper.pyx diff --git a/python/pyproject.toml b/python/pyproject.toml new file mode 100644 index 0000000..56f8955 --- /dev/null +++ b/python/pyproject.toml @@ -0,0 +1,58 @@ +[build-system] +requires = ["setuptools>=61.0", "cython>=3", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "mib2h5" +version = "0.0.1" +description = "Python wrapper for MIB to HDF5 conversion" +readme = "README.md" +requires-python = ">=3.10" +license = "MIT" +authors = [ + {name = "Timothy Poon", email = "timothy0626@gmail.com"}, +] +keywords = ["MIB", + "HDF5", + "MerlinEM", + "Quantum Detector", + "electron microscopy", + "data conversion", +] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Science/Research", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Cython", + "Topic :: Scientific/Engineering", +] + +[project.optional-dependencies] +test = [ + "pytest", + "h5py>=3.0", +] + +[tool.setuptools] +zip-safe = false + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.ruff] +line-length = 79 +target-version = "py310" + +[tool.ruff.lint] +select = [ + "E", + "F", + "UP", + "B", + "SIM", + "I", +] diff --git a/python/setup.py b/python/setup.py index 616ba66..e128736 100644 --- a/python/setup.py +++ b/python/setup.py @@ -1,11 +1,12 @@ -from setuptools import setup, Extension -from setuptools.command.build_ext import build_ext -from Cython.Build import cythonize -from pathlib import Path import os import subprocess +from pathlib import Path from subprocess import CalledProcessError +from Cython.Build import cythonize +from setuptools import Extension, setup +from setuptools.command.build_ext import build_ext + class AutotoolsError(Exception): """Exception raised when autotools configuration fails.""" @@ -130,8 +131,8 @@ def _find_hdf5_paths(): # verify hdf5 header exists if not _check_header_exists(hdf5_include, "hdf5.h"): - msg = (f"HDF5 header not found at '{hdf5_include}'. Please verify your " - "HDF5 installation.") + msg = (f"HDF5 header not found at '{hdf5_include}'. Please verify " + "your HDF5 installation.") raise FileNotFoundError(msg) return hdf5_include, hdf5_lib diff --git a/python/src/mib2h5/__init__.py b/python/src/mib2h5/__init__.py new file mode 100644 index 0000000..fa6fca1 --- /dev/null +++ b/python/src/mib2h5/__init__.py @@ -0,0 +1,9 @@ +"""mib2h5 - Python wrapper for MIB to HDF5 conversion. + +This package provides Python binding for converting MerlinEM MIB files +to HDF5 files. +""" + +from ._wrapper import convert + +__all__ = ["convert"] diff --git a/python/src/mib2h5/_wrapper.pyx b/python/src/mib2h5/_wrapper.pyx new file mode 100644 index 0000000..7537ff1 --- /dev/null +++ b/python/src/mib2h5/_wrapper.pyx @@ -0,0 +1,81 @@ +# cython: language_level=3 + +cdef extern from "mib_to_h5.h": + int mib_to_h5(const char *filename, + const char *output_directory, + const char *merlin_dset_name, + const char *compressor, + unsigned int shuffle, + unsigned int compression_level) + +def convert(str filename, + str output_directory="./", + str merlin_dset_name="MerlinData", + str compressor="blosclz", + int shuffle=2, + int compression_level=9): + """ + Convert a MIB file to HDF5 format. + + Parameters + ---------- + filename : str + Path to the input MIB file + output_directory : str, optional + Directory where the output HDF5 file will be saved (default: "./") + merlin_dset_name : str, optional + Name of the dataset in the HDF5 file (default: "MerlinData") + compressor : str, optional + Compression algorithm to use (default: "blosclz") + shuffle : int, optional + Shuffle filter setting (default: 2) + compression_level : int, optional + Compression level 0-9 (default: 9) + + Returns + ------- + int + 0 on success, negative value on error + + Raises + ------ + ValueError + If required parameters are missing or invalid + RuntimeError + If the conversion fails + """ + if not filename: + raise ValueError("Input filename cannot be empty.") + + if not output_directory: + raise ValueError("Output directory cannot be empty.") + + if not merlin_dset_name: + raise ValueError("Dataset name cannot be empty.") + + if shuffle < 0 or shuffle > 2: + raise ValueError("Shuffle must be 0, 1, or 2.") + + if compression_level < 0 or compression_level > 9: + raise ValueError("Compression level must be between 0 and 9.") + + # encode strings to bytes + cdef bytes b_filename = filename.encode() + cdef bytes b_output_directory = output_directory.encode() + cdef bytes b_merlin_dset_name = merlin_dset_name.encode() + cdef bytes b_compressor = compressor.encode() if compressor else b"" + + # call the C function + cdef int result = mib_to_h5( + b_filename, + b_output_directory, + b_merlin_dset_name, + b_compressor, + shuffle, + compression_level + ) + + if result != 0: + raise RuntimeError(f"Conversion failed with error code: {result}") + + return result From da4df0bdd9dd184b6be0b8507c40c85489cf19c0 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 27 Aug 2025 15:14:47 +0100 Subject: [PATCH 211/251] Add initial pyproject and MANIFEST.in --- python/MANIFEST.in | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 python/MANIFEST.in diff --git a/python/MANIFEST.in b/python/MANIFEST.in new file mode 100644 index 0000000..72b7464 --- /dev/null +++ b/python/MANIFEST.in @@ -0,0 +1,18 @@ +# include C source files from parent directory +include ../src/*.c +include ../src/*.h +include ../configure.ac +include ../Makefile.am +include ../Makefile.in +include ../aclocal.m4 + +# include Cython source +include src/mib2h5/_wrapper.pyx + +# exclude compiled/cached files +global-exclude *.o +global-exclude *.so +global-exclude __pycache__ +global-exclude *.pyc +global-exclude *.pyo +global-exclude *~ From 0e281aa803150e942e825f22c26da407d846e16f Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 27 Aug 2025 15:23:32 +0100 Subject: [PATCH 212/251] Add initial README file for Python wrapper --- python/README.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 python/README.md diff --git a/python/README.md b/python/README.md new file mode 100644 index 0000000..18fe8e9 --- /dev/null +++ b/python/README.md @@ -0,0 +1,58 @@ +# mib2h5 Python Wrapper + +Python bindings for `mib2h5`, the `.mib` to HDF5 converter. + +## Introduction + +This package provides a Python interface to convert MerlinEM `.mib` files from +Quantum Detector to HDF5 format (`.h5`). + +## Installation + +### Prerequisites + +- Python >= 3.10 +- Cython >= 3.0 +- HDF5 library (1.10.4 or newer) + +### pip + +```bash +# Set HDF5 location (if not in standard system paths) +export HDF5_ROOT=/path/to/hdf5 + +# Install the package +python -m pip install . + +# For development, install in editable mode +python -m pip install -e . +``` + +## Usage + +```python +import mib2h5 + +# Convert a MIB file to HDF5 +mib2h5.convert( + filename="input.mib", + output_directory="./output/", + merlin_dset_name="data", + compressor="blosclz", + shuffle=2, + compression_level=9 +) +``` + +## Parameters + +- `filename`: Path to input MIB file (required) +- `output_directory`: Directory for output HDF5 file (default: "./") +- `merlin_dset_name`: Name of dataset in HDF5 file (default: "MerlinData") +- `compressor`: Compression algorithm (default: "blosclz", use "" to disable) +- `shuffle`: Shuffle filter setting 0-2 (default: 2) +- `compression_level`: Compression level 0-9 (default: 9) + +## Licence + +MIT From 823e0eba2e4175c057a1e1e224e2b9bb6e99afbb Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Wed, 27 Aug 2025 17:20:18 +0100 Subject: [PATCH 213/251] Ignore autotools and Cython generated files --- .gitignore | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.gitignore b/.gitignore index 7cce8cb..682aed5 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,23 @@ doc/.build/* *__pycache__* *sg_execution_times.rst venv/* + +# autotools generated files +**/aclocal.m4 +**/autom4te.cache/ +**/compile +**/config.h +**/config.h.in +**/config.log +**/config.status +**/configure +**/depcomp +**/install-sh +**/missing +**/stamp-h1 +**/Makefile +**/Makefile.in +**/.deps/ + +# cython generated c files +**/_wrapper.c From 2e44d0ba2af4d5c1c095f3adca46828f5dfea45e Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 09:38:43 +0100 Subject: [PATCH 214/251] Put default values into a single file so it can be reused --- python/src/mib2h5/constants.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 python/src/mib2h5/constants.py diff --git a/python/src/mib2h5/constants.py b/python/src/mib2h5/constants.py new file mode 100644 index 0000000..e4a5658 --- /dev/null +++ b/python/src/mib2h5/constants.py @@ -0,0 +1,8 @@ +"""Constants for mib2h5 package.""" + +# default values matching C implementation +DEFAULT_OUTPUT_DIRECTORY = "./" +DEFAULT_DATASET_NAME = "MerlinData" +DEFAULT_COMPRESSOR = "blosclz" +DEFAULT_COMPRESSION_LEVEL = 9 +DEFAULT_SHUFFLE = 2 From 3b61abdac8a1a27cebfe6f56111302f1f4ae858d Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 09:39:30 +0100 Subject: [PATCH 215/251] Use default values from the constant file in the wrapper --- python/src/mib2h5/_wrapper.pyx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/python/src/mib2h5/_wrapper.pyx b/python/src/mib2h5/_wrapper.pyx index 7537ff1..211ad2b 100644 --- a/python/src/mib2h5/_wrapper.pyx +++ b/python/src/mib2h5/_wrapper.pyx @@ -1,5 +1,13 @@ # cython: language_level=3 +from .constants import ( + DEFAULT_COMPRESSION_LEVEL, + DEFAULT_COMPRESSOR, + DEFAULT_DATASET_NAME, + DEFAULT_OUTPUT_DIRECTORY, + DEFAULT_SHUFFLE, +) + cdef extern from "mib_to_h5.h": int mib_to_h5(const char *filename, const char *output_directory, @@ -9,11 +17,11 @@ cdef extern from "mib_to_h5.h": unsigned int compression_level) def convert(str filename, - str output_directory="./", - str merlin_dset_name="MerlinData", - str compressor="blosclz", - int shuffle=2, - int compression_level=9): + str output_directory=DEFAULT_OUTPUT_DIRECTORY, + str merlin_dset_name=DEFAULT_DATASET_NAME, + str compressor=DEFAULT_COMPRESSOR, + int shuffle=DEFAULT_SHUFFLE, + int compression_level=DEFAULT_COMPRESSION_LEVEL): """ Convert a MIB file to HDF5 format. From acc1e7c889b85237ed50894420249f3676a7ee07 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 09:40:01 +0100 Subject: [PATCH 216/251] Add cli mib2h5 --- python/pyproject.toml | 3 + python/src/mib2h5/cli.py | 116 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 python/src/mib2h5/cli.py diff --git a/python/pyproject.toml b/python/pyproject.toml index 56f8955..538ab75 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -37,6 +37,9 @@ test = [ "h5py>=3.0", ] +[project.scripts] +mib2h5 = "mib2h5.cli:main" + [tool.setuptools] zip-safe = false diff --git a/python/src/mib2h5/cli.py b/python/src/mib2h5/cli.py new file mode 100644 index 0000000..c6d0927 --- /dev/null +++ b/python/src/mib2h5/cli.py @@ -0,0 +1,116 @@ +"""Command-line interface for mib2h5 package.""" + +import argparse +import sys +from importlib.metadata import PackageNotFoundError, version + +from ._wrapper import convert +from .constants import ( + DEFAULT_COMPRESSION_LEVEL, + DEFAULT_COMPRESSOR, + DEFAULT_DATASET_NAME, + DEFAULT_OUTPUT_DIRECTORY, + DEFAULT_SHUFFLE, +) + + +def create_parser() -> argparse.ArgumentParser: + """Create argument parser for mib2h5 CLI. + + Returns + ------- + argparse.ArgumentParser + the argument parser for mib2h5 CLI + """ + parser = argparse.ArgumentParser( + description="Convert MIB file to HDF5 file", + prog="mib2h5" + ) + + parser.add_argument( + "-i", "--input", + dest="filename", + required=True, + help="input MIB file path" + ) + + parser.add_argument( + "-o", "--output-directory", + default=DEFAULT_OUTPUT_DIRECTORY, + help=f"output directory (default: {DEFAULT_OUTPUT_DIRECTORY})" + ) + + parser.add_argument( + "-d", "--merlin-dset-name", + default=DEFAULT_DATASET_NAME, + help=("Merlin frames dataset name in HDF5 file " + f"(default: {DEFAULT_DATASET_NAME})") + ) + + parser.add_argument( + "-c", "--compressor", + default=DEFAULT_COMPRESSOR, + help=f"compression used (default: {DEFAULT_COMPRESSOR})" + ) + + parser.add_argument( + "-s", "--shuffle", + type=int, + default=DEFAULT_SHUFFLE, + help=f"shuffle filter setting (default: {DEFAULT_SHUFFLE})" + ) + + parser.add_argument( + "-l", "--compression-level", + type=int, + default=DEFAULT_COMPRESSION_LEVEL, + help=f"compression level 0-9 (default: {DEFAULT_COMPRESSION_LEVEL})" + ) + + parser.add_argument( + "--version", + action="version", + version=_get_version() + ) + + return parser + + +def _get_version() -> str: + """Get package version. + + Returns + ------- + str + Package version string + """ + try: + return version("mib2h5") + except PackageNotFoundError: + return "unknown" + + +def main() -> int: + """Entry point for mib2h5 CLI. + + Returns + ------- + int + Exit code: 0 for success, non-zero for error + """ + parser = create_parser() + args = parser.parse_args() + result = convert( + filename=args.filename, + output_directory=args.output_directory, + merlin_dset_name=args.merlin_dset_name, + compressor=args.compressor, + shuffle=args.shuffle, + compression_level=args.compression_level + ) + + return result + + +if __name__ == "__main__": + sys.exit(main()) From fb27e8f3039d669e14653d51b241882b6221065f Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 09:41:10 +0100 Subject: [PATCH 217/251] Provide __verision__ attribute for backwards compatibility --- python/src/mib2h5/__init__.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/python/src/mib2h5/__init__.py b/python/src/mib2h5/__init__.py index fa6fca1..e73a676 100644 --- a/python/src/mib2h5/__init__.py +++ b/python/src/mib2h5/__init__.py @@ -4,6 +4,13 @@ to HDF5 files. """ +from importlib.metadata import PackageNotFoundError, version + from ._wrapper import convert -__all__ = ["convert"] +try: + __version__ = version("mib2h5") +except PackageNotFoundError: + __version__ = "unknown" + +__all__ = ["convert", "__version__"] From a721a58e7d0ca1697be70c6f960ea6b76a25df22 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 10:03:47 +0100 Subject: [PATCH 218/251] Align environment variable searching for HDF5 installation in Python wrapper with autotools --- python/setup.py | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/python/setup.py b/python/setup.py index e128736..734fb6f 100644 --- a/python/setup.py +++ b/python/setup.py @@ -75,13 +75,16 @@ def _run_configure(self): def _get_configure_args(self): """Get configure command arguments.""" - hdf5_root = os.environ.get("HDF5_ROOT") - if hdf5_root: - hdf5_path = Path(hdf5_root).resolve() - if not hdf5_path.exists(): - msg = f"HDF5_ROOT path does not exist: {hdf5_path}" - raise AutotoolsError(msg) - return ["./configure", f"--with-hdf5={hdf5_path}"] + # check hdf5 environment variables in order of priority + for env_var in ("HDF5_ROOT", "HDF5_HOME", "HDF5_DIR"): + hdf5_path_str = os.environ.get(env_var) + if hdf5_path_str: + hdf5_path = Path(hdf5_path_str).resolve() + if not hdf5_path.exists(): + msg = f"{env_var} path does not exist: {hdf5_path}" + raise AutotoolsError(msg) + print(f"Using {env_var}={hdf5_path} for configure") + return ["./configure", f"--with-hdf5={hdf5_path}"] return ["./configure"] @property @@ -110,11 +113,21 @@ def _get_library_path(root_path, lib_name="lib"): def _find_hdf5_paths(): """Find HDF5 include and library paths.""" - hdf5_root_env = os.environ.get("HDF5_ROOT") + # check hdf5 environment variables in order of priority + hdf5_root = None + for env_var in ("HDF5_ROOT", "HDF5_HOME", "HDF5_DIR"): + hdf5_path_str = os.environ.get(env_var) + if hdf5_path_str: + hdf5_root = Path(hdf5_path_str).resolve() + if hdf5_root.exists(): + print(f"Using {env_var}={hdf5_root} for HDF5") + break + else: + print(f"Warning: {env_var} is set but path doesn't exist: " + f"{hdf5_root}") + hdf5_root = None - if hdf5_root_env: - hdf5_root = Path(hdf5_root_env).resolve() - else: + if not hdf5_root: # try default paths for default_path in ("/usr", "/usr/local"): candidate = Path(default_path) @@ -122,8 +135,9 @@ def _find_hdf5_paths(): hdf5_root = candidate break else: - msg = ("HDF5 not found in default locations. Please set HDF5_ROOT " - "environment variable to your HDF5 installation.") + msg = ("HDF5 not found in default locations. Please set one of " + "HDF5_ROOT, HDF5_HOME, or HDF5_DIR environment variables " + "to your HDF5 installation.") raise FileNotFoundError(msg) hdf5_include = hdf5_root / "include" From 43533ea60a940ddf8afe1cd7d9da5ee93d1949c5 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 10:19:20 +0100 Subject: [PATCH 219/251] Increase lower bound of setuptool version to adhere PEP 639 for license field --- python/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pyproject.toml b/python/pyproject.toml index 538ab75..a14adfb 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61.0", "cython>=3", "wheel"] +requires = ["setuptools>=77.0", "cython>=3", "wheel"] build-backend = "setuptools.build_meta" [project] From 3c8e512a289c7460456addd01980e0e69a1e8dcd Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 16:40:18 +0100 Subject: [PATCH 220/251] Add public header for mib_to_h5 --- src/Makefile.am | 3 ++ src/mib2h5.h | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/mib2h5.h diff --git a/src/Makefile.am b/src/Makefile.am index 2ed4d69..caed3b0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,3 +4,6 @@ bin_PROGRAMS = mib2h5 # Source files mib2h5_SOURCES = main.c mib_to_h5.c utils.c io_header.c parser.c framebuffer.c hdf5_init.c hdf5_init_meta.c read.c append.c compress.c mib2h5_LDADD = -lhdf5 @LIBCOMPRESSION@ + +# Install public header +include_HEADERS = mib2h5.h diff --git a/src/mib2h5.h b/src/mib2h5.h new file mode 100644 index 0000000..111eaa4 --- /dev/null +++ b/src/mib2h5.h @@ -0,0 +1,90 @@ +// clang-format Language: C +/** + * @file mib2h5.h + * @brief Public API for mib2h5 library - MerlinEM MIB to HDF5 converter + * @version 0.0.1 + * + * This header defines the public API for converting MerlinEM detector + * output files (.mib) from Quantum Detector to HDF5 format (.h5). + * + * The library preserves all metadata and supports frame-by-frame processing + * for handling large datasets efficiently. + */ +#ifndef MIB2H5_H +#define MIB2H5_H + +#include + +#define MIB2H5_VERSION_MAJOR 0 +#define MIB2H5_VERSION_MINOR 0 +#define MIB2H5_VERSION_PATCH 1 +#define MIB2H5_VERSION "0.0.1" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Convert MIB files to HDF5 files + * + * Converts MerlinEM .mib files to HDF5 files, saves all the frames and + * optionally keeps their metadata. Each input .mib file produces a separate + * HDF5 output file with the same base name. + * + * @param[in] input_files Array of paths to input .mib files + * @param[in] num_input_files Number of files in input_files (must be >0) + * @param[in] output_dir Output directory (NULL uses current directory) + * @param[in] include_metadata If true, includes metadata of frames in HDF5 + * @param[in] dataset_key HDF5 dataset path for frames (NULL defaults to + * "/data") + * @param[in] metadata_key HDF5 group path for metadata (NULL defaults to + * "/metadata") + * @param[in] use_compression Enable Blosc compression if true + * @param[in] reshape_dims Reshape string like "10x10" (NOT YET IMPLEMENTED) + * @param[in] report_progress Enable progress reporting (NOT YET IMPLEMENTED) + * @param[in] timeout_seconds Conversion timeout in seconds, 0 for no limit + * (NOT YET IMPLEMENTED) + * + * @return 0 on success, -1 on error + * + * @note Output files are named by replacing .mib extension with .h5 + * @note If multiple files are provided, conversion continues even if one fails + * @note Some Blosc compression setting can be controlled by + * environment variables: + * - MIB2H5_SHUFFLE (default: 2, range: 0-2) + * - MIB2H5_COMPRESSION_LEVEL (default: 9, range: 0-9) + * + * @code + * // Example: Convert multiple files with metadata + * const char* files[] = {"data1.mib", "data2.mib"}; + * int result = mib_to_h5(files, 2, "output/", true, + * NULL, NULL, false, NULL, false, 0); + * if (result != 0) { + * fprintf(stderr, "Conversion failed: %s\n", mib_to_h5_last_error()); + * } + * @endcode + */ +int mib_to_h5(const char **input_files, + int num_input_files, + const char *output_dir, + bool include_metadata, + const char *dataset_key, + const char *metadata_key, + bool use_compression, + const char *reshape_dims, + bool report_progress, + unsigned int timeout_seconds); + +/** + * @brief Get the last error message from mib_to_h5 operations + * @warning This function is not yet implemented and always returns a + * placeholder + * @todo Implement proper thread-safe error message handling + */ +const char *mib_to_h5_last_error(void); + +#ifdef __cplusplus +} +#endif + +#endif // MIB2H5_H From 22844d1276b4d6d4daeb6c26e63cd35c351ecbdd Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 16:44:43 +0100 Subject: [PATCH 221/251] Handle multiple mib files and metadata inclusion as specified in the C API --- src/mib_to_h5.c | 140 ++++++++++++++++++++++++++++++++++++++++-------- src/mib_to_h5.h | 16 +++--- 2 files changed, 128 insertions(+), 28 deletions(-) diff --git a/src/mib_to_h5.c b/src/mib_to_h5.c index ab13719..f884946 100644 --- a/src/mib_to_h5.c +++ b/src/mib_to_h5.c @@ -5,6 +5,7 @@ #include "hdf5_init.h" #include "hdf5_init_meta.h" #include "macros.h" +#include "mib2h5.h" #include "parser.h" #include "read.h" #include "utils.h" @@ -15,12 +16,13 @@ #include #include -int mib_to_h5(const char *filename, - const char *output_directory, - const char *merlin_dset_name, - const char *compressor, - unsigned int shuffle, - unsigned int compression_level) +int mib_to_h5_single_file(const char *filename, + const char *output_directory, + const char *dataset_key, + bool include_metadata, + const char *compressor, + unsigned int shuffle, + unsigned int compression_level) { FILE *mib_ptr = NULL; char *output_file = NULL; @@ -38,7 +40,7 @@ int mib_to_h5(const char *filename, int ret = -1; // validate inputs - if (!filename || !output_directory || !merlin_dset_name) { + if (!filename || !output_directory || !dataset_key) { fprintf(stderr, "Error: Missing required parameters\n"); return -1; } @@ -157,24 +159,26 @@ int mib_to_h5(const char *filename, } // create main dataset - create_merlin_dataset(&merlin_dataset_id, file_id, merlin_dset_name, dtype, - dcpl, lcpl_id, frame_dim); + create_merlin_dataset(&merlin_dataset_id, file_id, dataset_key, dtype, dcpl, + lcpl_id, frame_dim); if (merlin_dataset_id < 0) { fprintf(stderr, "Error: Cannot create main dataset\n"); goto cleanup; } - // create metadata datasets - create_meta_mq1_fields_dataset(file_id, lcpl_id, meta_handle); + // create metadata datasets if requested + if (include_metadata) { + create_meta_mq1_fields_dataset(file_id, lcpl_id, meta_handle); - // create DAC datasets - size_t dac_size = sizeof(hid_t) * DAC_NUM_FIELDS * num_chips; - dac_handle = malloc(dac_size); - if (!dac_handle) { - fprintf(stderr, "Error: Cannot allocate memory for DAC handles\n"); - goto cleanup; + // create DAC datasets + size_t dac_size = sizeof(hid_t) * DAC_NUM_FIELDS * num_chips; + dac_handle = malloc(dac_size); + if (!dac_handle) { + fprintf(stderr, "Error: Cannot allocate memory for DAC handles\n"); + goto cleanup; + } + create_dac_dataset(num_chips, file_id, lcpl_id, dac_handle); } - create_dac_dataset(num_chips, file_id, lcpl_id, dac_handle); // allocate framebuffer allocate_frame_header(&fb); @@ -200,11 +204,13 @@ int mib_to_h5(const char *filename, // append frame data to dataset append_frame_to_dataset(merlin_dataset_id, &fb, cbytes); - // append metadata - append_meta_to_dataset(meta_handle, &fb); + // append metadata if requested + if (include_metadata) { + append_meta_to_dataset(meta_handle, &fb); - // append DAC data - append_dac_to_dataset(num_chips, dac_handle, &fb); + // append DAC data + append_dac_to_dataset(num_chips, dac_handle, &fb); + } // progress indicator if ((i + 1) % 100 == 0 || i == num_frames - 1) { @@ -262,3 +268,93 @@ int mib_to_h5(const char *filename, return ret; } + +int mib_to_h5(const char **input_files, + int num_input_files, + const char *output_dir, + bool include_metadata, + const char *dataset_key, + const char *metadata_key, + bool use_compression, + const char *reshape_dims, + bool report_progress, + unsigned int timeout_seconds) +{ + // validate inputs + if (!input_files || num_input_files <= 0) { + fprintf(stderr, "Error: No input files specified\n"); + return -1; + } + + // set defaults for optional parameters + const char *actual_output_dir = output_dir ? output_dir : "./"; + const char *actual_dataset_key = dataset_key ? dataset_key : "/data"; + + // handle unimplemented features with user messages + if (metadata_key) { + // TODO: implement custom metadata key support + fprintf(stderr, "Note: metadata_key parameter not yet implemented, using " + "default /metadata\n"); + } + + if (reshape_dims) { + // TODO: implement reshape dimensions support + fprintf(stderr, "Note: reshape_dims not yet implemented\n"); + } + + if (report_progress) { + // TODO: implement progress reporting + fprintf(stderr, "Note: report_progress not yet implemented\n"); + } + + if (timeout_seconds > 0) { + // TODO: implement timeout handling + fprintf(stderr, "Note: timeout_seconds not yet implemented\n"); + } + + // determine compression settings + const char *compressor = NULL; + unsigned int shuffle = 0; + unsigned int compression_level = 0; + + if (use_compression) { + compressor = "blosclz"; + + // check environment variables for compression settings + const char *shuffle_env = getenv("MIB2H5_SHUFFLE"); + const char *level_env = getenv("MIB2H5_COMPRESSION_LEVEL"); + + shuffle = shuffle_env ? (unsigned int) atoi(shuffle_env) : 2; + compression_level = level_env ? (unsigned int) atoi(level_env) : 9; + } + + // process each input file + int total_errors = 0; + for (int i = 0; i < num_input_files; ++i) { + if (!input_files[i]) { + fprintf(stderr, "Error: NULL input file at index %d\n", i); + total_errors++; + continue; + } + + printf("Processing file %d of %d: %s\n", i + 1, num_input_files, + input_files[i]); + + int result = mib_to_h5_single_file(input_files[i], actual_output_dir, + actual_dataset_key, include_metadata, + compressor, shuffle, compression_level); + + if (result != 0) { + fprintf(stderr, "Error: Failed to convert %s\n", input_files[i]); + total_errors++; + // continue processing other files instead of stopping + } + } + + return total_errors > 0 ? -1 : 0; +} + +const char *mib_to_h5_last_error(void) +{ + return "Error handling not yet implemented"; +} diff --git a/src/mib_to_h5.h b/src/mib_to_h5.h index 584a962..4c0e66b 100644 --- a/src/mib_to_h5.h +++ b/src/mib_to_h5.h @@ -2,11 +2,15 @@ #ifndef MIB_TO_H5_H #define MIB_TO_H5_H -int mib_to_h5(const char *filename, - const char *output_directory, - const char *merlin_dset_name, - const char *compressor, - unsigned int shuffle, - unsigned int compression_level); +#include + +// function for single file conversion +int mib_to_h5_single_file(const char *filename, + const char *output_directory, + const char *dataset_key, + bool include_metadata, + const char *compressor, + unsigned int shuffle, + unsigned int compression_level); #endif From 4ab98d81a613423644a70c9dd877721a7ce7bb39 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 16:59:33 +0100 Subject: [PATCH 222/251] Support multiple .mib file with long command-line options --- src/main.c | 139 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 113 insertions(+), 26 deletions(-) diff --git a/src/main.c b/src/main.c index 10947b5..a244ea0 100644 --- a/src/main.c +++ b/src/main.c @@ -1,55 +1,142 @@ #include "config.h" -#include "mib_to_h5.h" +#include "mib2h5.h" +#include +#include +#include +#include #include #include +#include #include +// long options structure for getopt_long +static const struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"no-metadata", no_argument, NULL, 'N'}, + {"with-metadata", no_argument, NULL, 'M'}, + {"output-dir", required_argument, NULL, 'o'}, + {"output-directory", required_argument, NULL, 'o'}, // alias for output-dir + {"dataset-key", required_argument, NULL, 'd'}, + {"metadata-key", required_argument, NULL, 'k'}, + {"compress", no_argument, NULL, 'c'}, + {"reshape-to", required_argument, NULL, 'r'}, + {"timeout", required_argument, NULL, 't'}, + {NULL, 0, NULL, 0}}; + +static void print_usage(const char *program_name) +{ + // clang-format off + fprintf(stderr, "Usage: %s [options] file1.mib [file2.mib ...]\n", program_name); + fprintf(stderr, "\nOptions:\n"); + fprintf(stderr, " -o, --output-dir DIR Output directory (default: current)\n"); + fprintf(stderr, " --output-directory DIR Alternative for --output-dir\n"); + fprintf(stderr, " -d, --dataset-key KEY Dataset key in HDF5 (default: /data)\n"); + fprintf(stderr, " -k, --metadata-key KEY Metadata key in HDF5 (default: /metadata)\n"); + fprintf(stderr, " - NOT YET IMPLEMENTED\n"); + fprintf(stderr, " -c, --compress Enable compression\n"); + fprintf(stderr, " -M, --with-metadata Include metadata in output (default)\n"); + fprintf(stderr, " -N, --no-metadata Exclude metadata from output\n"); + fprintf(stderr, " -r, --reshape-to DIMS Reshape dimensions (e.g., '10x10')\n"); + fprintf(stderr, " - NOT YET IMPLEMENTED\n"); + fprintf(stderr, " -t, --timeout SECS Timeout in seconds\n"); + fprintf(stderr, " - NOT YET IMPLEMENTED\n"); + fprintf(stderr, " -h, --help Show this help message\n"); + fprintf(stderr, "\nEnvironment variables:\n"); + fprintf(stderr, " MIB2H5_SHUFFLE Shuffle level for Blosc compression (default: 2)\n"); + fprintf(stderr, " MIB2H5_COMPRESSION_LEVEL Blosc compression level (default: 9)\n"); + // clang-format on +} + int main(int argc, char *argv[]) { int opt; - char *input_mib = NULL; - char *output_directory = "./"; - char *merlin_dset_name = "MerlinData"; - char *compressor = "blosclz"; - int compression_level = 9; - int shuffle = 2; - - while ((opt = getopt(argc, argv, "i:o:d:c:s:l:")) != -1) { + char *output_directory = NULL; + char *dataset_key = NULL; + char *metadata_key = NULL; + char *reshape_dims = NULL; + bool use_compression = false; + bool include_metadata = true; + bool report_progress = true; + unsigned int timeout_seconds = 900; + + // parse options + int option_index = 0; + while ((opt = getopt_long(argc, argv, "o:d:k:r:t:cMNh", long_options, + &option_index)) != -1) { switch (opt) { - case 'i': - input_mib = optarg; - break; case 'o': output_directory = optarg; break; case 'd': - merlin_dset_name = optarg; + dataset_key = optarg; + break; + case 'k': + metadata_key = optarg; break; + case 'r': + reshape_dims = optarg; + break; + case 't': { + char *endptr; + long val = strtol(optarg, &endptr, 10); + if (*endptr != '\0' || val < 0 || val > UINT_MAX) { + fprintf(stderr, "Error: Invalid timeout value: %s\n", optarg); + return 1; + } + timeout_seconds = (unsigned int) val; + } break; case 'c': - compressor = optarg; + use_compression = true; break; - case 's': - shuffle = atoi(optarg); + case 'M': + include_metadata = true; break; - case 'l': - compression_level = atoi(optarg); + case 'N': + include_metadata = false; break; + case 'h': + print_usage(argv[0]); + return 0; default: - fprintf( - stderr, - "Usage: -i input_mib -o output_directory -d merlin_dataset_name -c " - "compressor -s shuffle -l compression_level\n"); + print_usage(argv[0]); return 1; } } - if (input_mib == NULL) { - fprintf(stderr, "Error: input file must be specified\n"); + // collect input files from remaining arguments + int num_input_files = argc - optind; + if (num_input_files <= 0) { + fprintf(stderr, "Error: No input files specified\n\n"); + print_usage(argv[0]); return 1; } - int status = mib_to_h5(input_mib, output_directory, merlin_dset_name, - compressor, shuffle, compression_level); + const char **input_files = + (const char **) malloc((size_t) num_input_files * sizeof(char *)); + if (input_files == NULL) { + fprintf(stderr, "Error: Cannot allocate memory for input files\n"); + return 1; + } + + for (int i = 0; i < num_input_files; ++i) { + input_files[i] = argv[optind + i]; + } + + int status = + mib_to_h5(input_files, num_input_files, output_directory, include_metadata, + dataset_key, metadata_key, use_compression, reshape_dims, + report_progress, timeout_seconds); + + free(input_files); + + if (status != 0) { + const char *error_msg = mib_to_h5_last_error(); + if (error_msg != NULL) { + fprintf(stderr, "Error: %s\n", error_msg); + } else { + fprintf(stderr, "Error: Unknown conversion error (status: %d)\n", status); + } + } return status; } From 751a8f87aba05362cd730f71e99a7b74162549fe Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 17:01:01 +0100 Subject: [PATCH 223/251] Update README with long options, env var and metadata control --- README.md | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9c26767..bbd160e 100644 --- a/README.md +++ b/README.md @@ -110,18 +110,48 @@ This will create `file1.h5`, `file2.h5` and `file3.h5` in the directory #### Advanced Options -Convert with compression, custom dataset key, and reshape dimensions: +Convert with compression, custom dataset key, and excluding metadata: ```bash -mib2h5 -c -d '/rawdata' -r '10x10' -t 300 input.mib +mib2h5 -c -d '/rawdata' -N -- input.mib ``` This will: - enable Blosc compression - store the frames at the dataset key `/rawdata` in the HDF5 file -- reshape the data to `(10, 10, det_y, det_x)` if there are 100 frames with -dimensions of `(det_y, det_x)`. +- exclude metadata from the output (using `-N` or `--no-metadata`) + +#### Using Long Options + +Long options make commands more readable and self-documenting. You can find the +list of long options by `mib2h5 --help`. + +#### Metadata Control + +By default, metadata is included in the HDF5 output. You can control this +behavior: + +```bash +# Explicitly include metadata (default behavior) +mib2h5 -M input.mib +mib2h5 --with-metadata input.mib + +# Exclude metadata from output +mib2h5 -N input.mib +mib2h5 --no-metadata input.mib +``` + +#### Environment Variables + +When compression is enabled with `-c`, you can fine-tune the Blosc compression +settings: + +```bash +export MIB2H5_SHUFFLE=0 # Shuffle level (0-2, default: 2) +export MIB2H5_COMPRESSION_LEVEL=5 # Compression level (0-9, default: 9) +mib2h5 -c input.mib +``` ### C API Examples From 27e495931d34f6e28550f31e638b74b32de1afdc Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 21:54:11 +0100 Subject: [PATCH 224/251] Update build instruction --- README.md | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bbd160e..63e0a13 100644 --- a/README.md +++ b/README.md @@ -49,21 +49,63 @@ Below shows the hierarchy of the resulting HDF5 file: - GCC compiler (7.4 or newer, older versions may work) - HDF5 development libraries (1.10.4 or newer) - Make (3.82 or newer) +- GNU Autotools (autoconf >= 2.64, automake) - only required when building +the latest version #### Building from Source ```bash -# Clone the repository +# Download and extract the release tarball +tar xzf mib2h5-X.Y.Z.tar.gz +cd mib2h5-X.Y.Z +./configure --prefix=/path/to/install +make +make install +``` + +Without `--prefix`, the library will be installed to `/usr/local`. + +#### Building the Latest Version + +For the latest version: + +```bash git clone git@github.com:ePSIC-DLS/mib2h5.git cd mib2h5 -# Configure and build +# Generate configure script (requires GNU Autotools) +autoreconf -i + +# Then follow the standard build process ./configure --prefix=/path/to/install make make install ``` -Without `--prefix`, the library will be installed to `/usr/local`. +#### Configuration Options + +The configure script supports several options: + +##### HDF5 Location + +- `--with-hdf5=/path/to/hdf5` +- It also recognises the environment variables `HDF5_ROOT`, `HDF5_HOME` +and `HDF5_DIR` + +##### Compression Support + +- `--enable-compression`: Enable Blosc compression (requires +[c-blosc](https://github.com/Blosc/c-blosc) and +[hdf5-blosc](https://github.com/Blosc/hdf5-blosc)) +- `--with-blosc=/path/to/blosc` +- `--with-hdf5-blosc=/path/to/hdf5-blosc` + +##### Build Variants + +- `--enable-debug`: Debug build with symbols and static analysis +- `--enable-asan`: For memory debugging + +Run `./configure --help` for all available options. ### Python From c5e8edab488773290d95908da94dfed8f5c95d2e Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 22:16:52 +0100 Subject: [PATCH 225/251] Migrate Python information to the README of Python wrapper --- README.md | 75 ++-------------------------------- python/README.md | 103 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 85 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index 63e0a13..d37fe57 100644 --- a/README.md +++ b/README.md @@ -109,21 +109,7 @@ Run `./configure --help` for all available options. ### Python -#### Prerequisites - -- Python (3.9 or newer) - -#### Via pip - -```bash -python -m pip install mib2h5 -``` - -#### Via conda - -```bash -conda install -c conda-forge mib2h5 -``` +For Python installation and usage, please refer to the [Python wrapper documentation](python/README.md). ## Usage @@ -260,45 +246,6 @@ int main() { } ``` -### Python API Examples - -#### Basic Python Example - -```python -from mib2h5 import convert - -# Basic conversion -try: - convert("input.mib") -except (ValueError, RuntimeError): - print("Conversion failed.") -else: - print("Conversion successful!") -``` - -#### Advanced Python Example - -```python -from mib2h5 import convert - -try: - convert( - ["file1.mib", "file2.mib", "file3.mib"], - output_dir="/path/to/output", - include_metadata=True, - dataset_key="/rawdata", - metadata_key="/meta", - use_compression=True, - reshape_dims="10x10", - report_progress=True, - timeout_seconds=300 - ) -except (ValueError, RuntimeError): - print("Conversion failed.") -else: - print("Conversion successful!") -``` - ## API Reference ### C API @@ -320,24 +267,8 @@ int mib_to_h5( const char* mib_to_h5_last_error(void); ``` -### Python API - -```python -convert( - input_files, - output_dir=None, - include_metadata=True, - dataset_key="/data", - metadata_key="/metadata", - use_compression=False, - reshape_dims=None, - report_progress=True, - timeout_seconds=900 -) -``` - -For detailed parameter descriptions, refer to the header file `mib2h5.h` or the -Python docstrings. +For the Python API reference and detailed parameter descriptions, see the +[Python wrapper documentation](python/README.md). ## Contributing diff --git a/python/README.md b/python/README.md index 18fe8e9..ea4cc67 100644 --- a/python/README.md +++ b/python/README.md @@ -12,10 +12,30 @@ Quantum Detector to HDF5 format (`.h5`). ### Prerequisites - Python >= 3.10 -- Cython >= 3.0 - HDF5 library (1.10.4 or newer) +- Cython >= 3.0 - only required when building from source -### pip +### Via pip + +```bash +python -m pip install mib2h5 +``` + +### Via conda + +```bash +conda install -c conda-forge mib2h5 +``` + +### Via pipx + +You can use `pipx` to install only the command-line tool `mib2h5`: + +```bash +pipx install mib2h5 +``` + +### Building from Source ```bash # Set HDF5 location (if not in standard system paths) @@ -28,30 +48,71 @@ python -m pip install . python -m pip install -e . ``` -## Usage +## Examples + +### Basic Example ```python -import mib2h5 - -# Convert a MIB file to HDF5 -mib2h5.convert( - filename="input.mib", - output_directory="./output/", - merlin_dset_name="data", - compressor="blosclz", - shuffle=2, - compression_level=9 -) +from mib2h5 import convert + +try: + convert("input.mib") +except (ValueError, RuntimeError): + print("Conversion failed.") +else: + print("Conversion successful!") ``` -## Parameters +### Advanced Example + +```python +from mib2h5 import convert + +try: + convert( + ["file1.mib", "file2.mib", "file3.mib"], + output_dir="/path/to/output", + include_metadata=True, + dataset_key="/rawdata", + metadata_key="/meta", + use_compression=True, + reshape_to="10x10", + report_progress=True, + timeout_seconds=300 + ) +except (ValueError, RuntimeError): + print("Conversion failed.") +else: + print("Conversion successful!") +``` + +## API Reference + +```python +convert( + input_files, + output_dir=None, + include_metadata=True, + dataset_key="/data", + metadata_key="/metadata", + use_compression=False, + reshape_to=None, + report_progress=True, + timeout_seconds=900 +) +``` -- `filename`: Path to input MIB file (required) -- `output_directory`: Directory for output HDF5 file (default: "./") -- `merlin_dset_name`: Name of dataset in HDF5 file (default: "MerlinData") -- `compressor`: Compression algorithm (default: "blosclz", use "" to disable) -- `shuffle`: Shuffle filter setting 0-2 (default: 2) -- `compression_level`: Compression level 0-9 (default: 9) +### Parameters + +- `input_files`: Path to input MIB file(s) (string or list of strings) +- `output_dir`: Directory for output HDF5 file(s) (default: current directory) +- `include_metadata`: Whether to include metadata in HDF5 file (default: True) +- `dataset_key`: HDF5 dataset key for frames (default: "/data") +- `metadata_key`: HDF5 group key for metadata (default: "/metadata") +- `use_compression`: Enable compression (default: False) +- `reshape_to`: Reshape dimensions string like "10x10" (default: None) +- `report_progress`: Report conversion progress (default: True) +- `timeout_seconds`: Timeout in seconds (default: 900) ## Licence From c471a96312b24d9dad7be09cd8e4aa23003e4d78 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 23:09:31 +0100 Subject: [PATCH 226/251] Update default values in Python wrapper --- python/src/mib2h5/_wrapper.pyx | 11 +++++++---- python/src/mib2h5/constants.py | 13 ++++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/python/src/mib2h5/_wrapper.pyx b/python/src/mib2h5/_wrapper.pyx index 211ad2b..10166f3 100644 --- a/python/src/mib2h5/_wrapper.pyx +++ b/python/src/mib2h5/_wrapper.pyx @@ -1,11 +1,14 @@ # cython: language_level=3 from .constants import ( - DEFAULT_COMPRESSION_LEVEL, - DEFAULT_COMPRESSOR, - DEFAULT_DATASET_NAME, DEFAULT_OUTPUT_DIRECTORY, - DEFAULT_SHUFFLE, + DEFAULT_DATASET_KEY, + DEFAULT_INCLUDE_METADATA, + DEFAULT_METADATA_KEY, + DEFAULT_USE_COMPRESSION, + DEFAULT_RESHAPE_DIMS, + DEFAULT_REPORT_PROGRESS, + DEFAULT_TIMEOUT_SECONDS, ) cdef extern from "mib_to_h5.h": diff --git a/python/src/mib2h5/constants.py b/python/src/mib2h5/constants.py index e4a5658..2fa5de3 100644 --- a/python/src/mib2h5/constants.py +++ b/python/src/mib2h5/constants.py @@ -1,8 +1,11 @@ """Constants for mib2h5 package.""" # default values matching C implementation -DEFAULT_OUTPUT_DIRECTORY = "./" -DEFAULT_DATASET_NAME = "MerlinData" -DEFAULT_COMPRESSOR = "blosclz" -DEFAULT_COMPRESSION_LEVEL = 9 -DEFAULT_SHUFFLE = 2 +DEFAULT_OUTPUT_DIRECTORY = None +DEFAULT_DATASET_KEY = "/data" +DEFAULT_INCLUDE_METADATA = True +DEFAULT_METADATA_KEY = "/metadata" +DEFAULT_USE_COMPRESSION = False +DEFAULT_RESHAPE_DIMS = None +DEFAULT_REPORT_PROGRESS = True +DEFAULT_TIMEOUT_SECONDS = 900 From bb6fa7af6e1e69eaa132f34dc91f8f18e8ca8495 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 23:10:46 +0100 Subject: [PATCH 227/251] Use the single file version of mib_to_h5 in Python wrapper --- python/src/mib2h5/_wrapper.pyx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/python/src/mib2h5/_wrapper.pyx b/python/src/mib2h5/_wrapper.pyx index 10166f3..fbea0de 100644 --- a/python/src/mib2h5/_wrapper.pyx +++ b/python/src/mib2h5/_wrapper.pyx @@ -12,12 +12,13 @@ from .constants import ( ) cdef extern from "mib_to_h5.h": - int mib_to_h5(const char *filename, - const char *output_directory, - const char *merlin_dset_name, - const char *compressor, - unsigned int shuffle, - unsigned int compression_level) + int mib_to_h5_single_file(const char *filename, + const char *output_directory, + const char *dataset_key, + bint include_metadata, + const char *compressor, + unsigned int shuffle, + unsigned int compression_level) def convert(str filename, str output_directory=DEFAULT_OUTPUT_DIRECTORY, From a7b021a9eeae389633b20747d54c293e27e7a7a8 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 23:25:08 +0100 Subject: [PATCH 228/251] Handle multiple input files in Python wrapper --- python/src/mib2h5/_wrapper.pyx | 155 ++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 49 deletions(-) diff --git a/python/src/mib2h5/_wrapper.pyx b/python/src/mib2h5/_wrapper.pyx index fbea0de..7a54542 100644 --- a/python/src/mib2h5/_wrapper.pyx +++ b/python/src/mib2h5/_wrapper.pyx @@ -20,74 +20,131 @@ cdef extern from "mib_to_h5.h": unsigned int shuffle, unsigned int compression_level) -def convert(str filename, - str output_directory=DEFAULT_OUTPUT_DIRECTORY, - str merlin_dset_name=DEFAULT_DATASET_NAME, - str compressor=DEFAULT_COMPRESSOR, - int shuffle=DEFAULT_SHUFFLE, - int compression_level=DEFAULT_COMPRESSION_LEVEL): +def convert(input_files, + output_dir=DEFAULT_OUTPUT_DIRECTORY, + bint include_metadata=DEFAULT_INCLUDE_METADATA, + str dataset_key=DEFAULT_DATASET_KEY, + str metadata_key=DEFAULT_METADATA_KEY, + bint use_compression=DEFAULT_USE_COMPRESSION, + reshape_dims=DEFAULT_RESHAPE_DIMS, + bint report_progress=DEFAULT_REPORT_PROGRESS, + int timeout_seconds=DEFAULT_TIMEOUT_SECONDS): """ - Convert a MIB file to HDF5 format. + Convert MIB file(s) to HDF5 file(s). Parameters ---------- - filename : str - Path to the input MIB file - output_directory : str, optional - Directory where the output HDF5 file will be saved (default: "./") - merlin_dset_name : str, optional - Name of the dataset in the HDF5 file (default: "MerlinData") - compressor : str, optional - Compression algorithm to use (default: "blosclz") - shuffle : int, optional - Shuffle filter setting (default: 2) - compression_level : int, optional - Compression level 0-9 (default: 9) + input_files : str or list of str + Path(s) to the input MIB file(s) + output_dir : str, optional + Directory where the output HDF5 file(s) will be saved (default: + current directory) + include_metadata : bool, optional + Whether to include metadata in the HDF5 file (default: True) + dataset_key : str, optional + HDF5 dataset key for frames (default: "/data") + metadata_key : str, optional + HDF5 group path for metadata (default: "/metadata") + use_compression : bool, optional + Enable Blosc compression if available (default: False) + Note: Blosc compression settings can be controlled via + environment variables: + - MIB2H5_SHUFFLE (0-2, default: 2) + - MIB2H5_COMPRESSION_LEVEL (0-9, default: 9) + reshape_dims : str, optional + Reshape dimensions string like "10x10" (default: None) + report_progress : bool, optional + Report conversion progress (default: True) + timeout_seconds : int, optional + Timeout in seconds, 0 for no limit (default: 900) Returns ------- - int - 0 on success, negative value on error + None Raises ------ ValueError If required parameters are missing or invalid RuntimeError - If the conversion fails + If the conversion fails for any file """ - if not filename: - raise ValueError("Input filename cannot be empty.") + # ensure input_files is a list + if isinstance(input_files, str): + files = [input_files] + else: + files = list(input_files) - if not output_directory: - raise ValueError("Output directory cannot be empty.") + if not files: + raise ValueError("No input files provided") - if not merlin_dset_name: - raise ValueError("Dataset name cannot be empty.") + if not dataset_key: + raise ValueError("Dataset key cannot be empty") - if shuffle < 0 or shuffle > 2: - raise ValueError("Shuffle must be 0, 1, or 2.") + if timeout_seconds < 0: + raise ValueError("Timeout must be non-negative") - if compression_level < 0 or compression_level > 9: - raise ValueError("Compression level must be between 0 and 9.") + # prepare output directory + cdef bytes b_output_dir = output_dir.encode() if output_dir else b"./" + cdef bytes b_dataset_key = dataset_key.encode() - # encode strings to bytes - cdef bytes b_filename = filename.encode() - cdef bytes b_output_directory = output_directory.encode() - cdef bytes b_merlin_dset_name = merlin_dset_name.encode() - cdef bytes b_compressor = compressor.encode() if compressor else b"" + # determine compressor string based on use_compression + cdef bytes b_compressor = b"blosclz" if use_compression else b"" - # call the C function - cdef int result = mib_to_h5( - b_filename, - b_output_directory, - b_merlin_dset_name, - b_compressor, - shuffle, - compression_level - ) + # use default values for shuffle and compression_level + # these may be overridden by environment variables if provided + cdef unsigned int shuffle = 2 if use_compression else 0 + cdef unsigned int compression_level = 9 if use_compression else 0 - if result != 0: - raise RuntimeError(f"Conversion failed with error code: {result}") + # track errors for reporting + errors = [] + successful = [] - return result + # process each file + cdef bytes b_filename + cdef int result + + for filename in files: + if not filename: + errors.append((filename, "Empty filename")) + continue + + # encode filename + b_filename = filename.encode() + + # call the C function for single file + result = mib_to_h5_single_file( + b_filename, + b_output_dir, + b_dataset_key, + include_metadata, + b_compressor, + shuffle, + compression_level + ) + + if result == 0: + successful.append(filename) + else: + errors.append((filename, + f"Conversion failed with error code: {result}") + ) + + + # report succeeded and failed files if there is error + if errors: + error_messages = [] + for filename, msg in errors: + error_messages.append(f"{filename}: {msg}") + + error_report = "\n".join(error_messages) + + if successful: + success_msg = f"Successfully converted {len(successful)} file(s)" + failure_msg = (f"Failed to convert {len(errors)} " + f"file(s):\n{error_report}") + raise RuntimeError(f"{success_msg}\n{failure_msg}") + else: + msg = (f"Failed to convert all {len(errors)} " + f"file(s):\n{error_report}") + raise RuntimeError(msg) From 9c7f09ddfd398f27536e3a1df432a74fe2d3edee Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 23:46:20 +0100 Subject: [PATCH 229/251] Modify Python cli to support multiple input files --- python/src/mib2h5/cli.py | 111 +++++++++++++++++++++++++++------------ 1 file changed, 77 insertions(+), 34 deletions(-) diff --git a/python/src/mib2h5/cli.py b/python/src/mib2h5/cli.py index c6d0927..881b008 100644 --- a/python/src/mib2h5/cli.py +++ b/python/src/mib2h5/cli.py @@ -3,14 +3,17 @@ import argparse import sys from importlib.metadata import PackageNotFoundError, version +from pathlib import Path from ._wrapper import convert from .constants import ( - DEFAULT_COMPRESSION_LEVEL, - DEFAULT_COMPRESSOR, - DEFAULT_DATASET_NAME, + DEFAULT_DATASET_KEY, + DEFAULT_INCLUDE_METADATA, + DEFAULT_METADATA_KEY, DEFAULT_OUTPUT_DIRECTORY, - DEFAULT_SHUFFLE, + DEFAULT_REPORT_PROGRESS, + DEFAULT_TIMEOUT_SECONDS, + DEFAULT_USE_COMPRESSION, ) @@ -23,48 +26,69 @@ def create_parser() -> argparse.ArgumentParser: the argument parser for mib2h5 CLI """ parser = argparse.ArgumentParser( - description="Convert MIB file to HDF5 file", - prog="mib2h5" + description="Convert MIB file(s) to HDF5 file(s)", + prog="mib2h5", + epilog="Environment variables:\n" + " MIB2H5_SHUFFLE Shuffle level for Blosc compression (0-2, default: 2)\n" + " MIB2H5_COMPRESSION_LEVEL Blosc compression level (0-9, default: 9)", + formatter_class=argparse.RawDescriptionHelpFormatter ) + # positional arguments for input files parser.add_argument( - "-i", "--input", - dest="filename", - required=True, - help="input MIB file path" + "input_files", + nargs="+", + help="input MIB file(s) to convert" ) + # optional arguments parser.add_argument( - "-o", "--output-directory", + "-o", "--output-dir", default=DEFAULT_OUTPUT_DIRECTORY, - help=f"output directory (default: {DEFAULT_OUTPUT_DIRECTORY})" + help="output directory for HDF5 files (default: current directory)" ) parser.add_argument( - "-d", "--merlin-dset-name", - default=DEFAULT_DATASET_NAME, - help=("Merlin frames dataset name in HDF5 file " - f"(default: {DEFAULT_DATASET_NAME})") + "-d", "--dataset-key", + default=DEFAULT_DATASET_KEY, + help=f"HDF5 dataset path for frames (default: {DEFAULT_DATASET_KEY})" ) parser.add_argument( - "-c", "--compressor", - default=DEFAULT_COMPRESSOR, - help=f"compression used (default: {DEFAULT_COMPRESSOR})" + "-c", "--compression", + action="store_true", + default=DEFAULT_USE_COMPRESSION, + help="enable Blosc compression (settings via env vars)" ) parser.add_argument( - "-s", "--shuffle", - type=int, - default=DEFAULT_SHUFFLE, - help=f"shuffle filter setting (default: {DEFAULT_SHUFFLE})" + "-N", "--no-metadata", + action="store_false", + dest="include_metadata", + default=DEFAULT_INCLUDE_METADATA, + help="exclude metadata from HDF5 output" + ) + + parser.add_argument( + "--metadata-key", + default=DEFAULT_METADATA_KEY, + help=f"HDF5 group path for metadata (default: {DEFAULT_METADATA_KEY})" ) parser.add_argument( - "-l", "--compression-level", + "--no-progress", + action="store_false", + dest="report_progress", + default=DEFAULT_REPORT_PROGRESS, + help="disable progress reporting" + ) + + parser.add_argument( + "--timeout", type=int, - default=DEFAULT_COMPRESSION_LEVEL, - help=f"compression level 0-9 (default: {DEFAULT_COMPRESSION_LEVEL})" + default=DEFAULT_TIMEOUT_SECONDS, + help=("timeout in seconds, 0 for no limit " + f"(default: {DEFAULT_TIMEOUT_SECONDS})") ) parser.add_argument( @@ -100,16 +124,35 @@ def main() -> int: """ parser = create_parser() args = parser.parse_args() - result = convert( - filename=args.filename, - output_directory=args.output_directory, - merlin_dset_name=args.merlin_dset_name, - compressor=args.compressor, - shuffle=args.shuffle, - compression_level=args.compression_level + + # validate input files exist + missing_files = [] + for filepath in args.input_files: + if not Path(filepath).exists: + missing_files.append(filepath) + + if missing_files: + missing_files_msg = "\n".join(missing_files) + msg = f"The following input files do not exist: {missing_files_msg}" + raise FileNotFoundError(msg) + + if args.timeout < 0: + raise ValueError("Timeout must be non-negative") + + # call the conversion function + convert( + input_files=args.input_files, + output_dir=args.output_dir, + include_metadata=args.include_metadata, + dataset_key=args.dataset_key, + metadata_key=args.metadata_key, + use_compression=args.compression, + reshape_dims=None, + report_progress=args.report_progress, + timeout_seconds=args.timeout ) - return result + return 0 if __name__ == "__main__": From e170607edfbddd1ad98edf95c579bf2007ffe885 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Thu, 28 Aug 2025 23:56:25 +0100 Subject: [PATCH 230/251] Update Python README to reflect multiple input files usage --- python/README.md | 93 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 30 deletions(-) diff --git a/python/README.md b/python/README.md index ea4cc67..0e17a17 100644 --- a/python/README.md +++ b/python/README.md @@ -48,42 +48,63 @@ python -m pip install . python -m pip install -e . ``` -## Examples +## Usage -### Basic Example +### Command-line Interface + +This is the same as in `mib2h5`, see the usage [here](../README.md). + +### Python API + +#### Basic Example ```python from mib2h5 import convert -try: - convert("input.mib") -except (ValueError, RuntimeError): - print("Conversion failed.") -else: - print("Conversion successful!") +# Convert a single file +convert("input.mib") + +# Convert with custom output directory +convert("input.mib", output_dir="/path/to/output") ``` -### Advanced Example +#### Advanced Example ```python from mib2h5 import convert +# Convert multiple files +files = ["file1.mib", "file2.mib", "file3.mib"] +convert( + files, + output_dir="/path/to/output", + include_metadata=True, + dataset_key="/rawdata", + use_compression=True +) + +# Handle errors for multiple files try: - convert( - ["file1.mib", "file2.mib", "file3.mib"], - output_dir="/path/to/output", - include_metadata=True, - dataset_key="/rawdata", - metadata_key="/meta", - use_compression=True, - reshape_to="10x10", - report_progress=True, - timeout_seconds=300 - ) -except (ValueError, RuntimeError): - print("Conversion failed.") -else: - print("Conversion successful!") + convert(files, output_dir="/path/to/output") +except RuntimeError as e: + print(f"Some files failed to convert:\n{e}") +``` + +#### Compression Control + +Compression is controlled via environment variables when +`use_compression=True`: + +```python +import os +from mib2h5 import convert + +# Set compression parameters +os.environ['MIB2H5_SHUFFLE'] = '2' # 0-2, default: 2 +os.environ['MIB2H5_COMPRESSION_LEVEL'] = '5' # 0-9, default: 9 + +# Convert with compression +convert("input.mib", use_compression=True) ``` ## API Reference @@ -96,7 +117,7 @@ convert( dataset_key="/data", metadata_key="/metadata", use_compression=False, - reshape_to=None, + reshape_dims=None, report_progress=True, timeout_seconds=900 ) @@ -107,12 +128,24 @@ convert( - `input_files`: Path to input MIB file(s) (string or list of strings) - `output_dir`: Directory for output HDF5 file(s) (default: current directory) - `include_metadata`: Whether to include metadata in HDF5 file (default: True) -- `dataset_key`: HDF5 dataset key for frames (default: "/data") -- `metadata_key`: HDF5 group key for metadata (default: "/metadata") -- `use_compression`: Enable compression (default: False) -- `reshape_to`: Reshape dimensions string like "10x10" (default: None) +- `dataset_key`: HDF5 dataset path for frames (default: "/data") +- `metadata_key`: HDF5 group path for metadata (default: "/metadata") +*[Not yet implemented]* +- `use_compression`: Enable Blosc compression if available (default: False) +- `reshape_dims`: Reshape dimensions string like "10x10" (default: None) +*[Not yet implemented]* - `report_progress`: Report conversion progress (default: True) -- `timeout_seconds`: Timeout in seconds (default: 900) +*[Not yet implemented]* +- `timeout_seconds`: Timeout in seconds, 0 for no limit (default: 900) +*[Not yet implemented]* + +### Notes + +- When converting multiple files, the function continues processing remaining +files even if some fail +- All errors are collected and reported together at the end +- Compression settings are controlled via environment variables +`MIB2H5_SHUFFLE` and `MIB2H5_COMPRESSION_LEVEL` ## Licence From b557f84d04e7d36aa0db4b4c9cf6b2e2b77e2158 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 5 Sep 2025 07:56:47 +0100 Subject: [PATCH 231/251] Add option to display version --- src/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index a244ea0..dc2a62f 100644 --- a/src/main.c +++ b/src/main.c @@ -12,6 +12,7 @@ // long options structure for getopt_long static const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, {"no-metadata", no_argument, NULL, 'N'}, {"with-metadata", no_argument, NULL, 'M'}, {"output-dir", required_argument, NULL, 'o'}, @@ -40,6 +41,7 @@ static void print_usage(const char *program_name) fprintf(stderr, " - NOT YET IMPLEMENTED\n"); fprintf(stderr, " -t, --timeout SECS Timeout in seconds\n"); fprintf(stderr, " - NOT YET IMPLEMENTED\n"); + fprintf(stderr, " -v, --version Display the version\n"); fprintf(stderr, " -h, --help Show this help message\n"); fprintf(stderr, "\nEnvironment variables:\n"); fprintf(stderr, " MIB2H5_SHUFFLE Shuffle level for Blosc compression (default: 2)\n"); @@ -61,7 +63,7 @@ int main(int argc, char *argv[]) // parse options int option_index = 0; - while ((opt = getopt_long(argc, argv, "o:d:k:r:t:cMNh", long_options, + while ((opt = getopt_long(argc, argv, "o:d:k:r:t:cMNvh", long_options, &option_index)) != -1) { switch (opt) { case 'o': @@ -94,6 +96,10 @@ int main(int argc, char *argv[]) case 'N': include_metadata = false; break; + case 'v': + printf("%d.%d.%d\n", MIB2H5_VERSION_MAJOR, MIB2H5_VERSION_MINOR, + MIB2H5_VERSION_PATCH); + return 0; case 'h': print_usage(argv[0]); return 0; From 378e7829ab743fa057b4896fb8e63e74f675fa98 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 5 Sep 2025 09:18:31 +0100 Subject: [PATCH 232/251] Display the actual specified path to find hdf5 library --- configure.ac | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 8685105..d1bde56 100644 --- a/configure.ac +++ b/configure.ac @@ -28,7 +28,7 @@ AC_ARG_WITH([hdf5], HDF5_OK=no AS_IF([test -n "$HDFDIR"], [ - AC_MSG_NOTICE([Test HDFDIR provided]) + AC_MSG_NOTICE([Testing HDF5 at $HDFDIR]) CPPFLAGS="$CPPFLAGS -I$HDFDIR/include" LDFLAGS="$LDFLAGS -L$HDFDIR/lib" @@ -37,13 +37,13 @@ AS_IF([test -n "$HDFDIR"], [ AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) HDF5_OK=yes ], [ - AC_MSG_NOTICE([libhdf5 not found on HDFDIR]) + AC_MSG_NOTICE([libhdf5 not found at $HDFDIR/lib]) AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HDFDIR/include||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$HDFDIR/lib||g"`]) HDF5_OK=no ]) ], [ - AC_MSG_NOTICE([hdf5.h not found on HDFDIR]) + AC_MSG_NOTICE([hdf5.h not found at $HDFDIR/include]) AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HDFDIR/include||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$HDFDIR/lib||g"`]) HDF5_OK=no @@ -84,11 +84,13 @@ if test "x$HDF5_OK" != xyes; then HDFDIR="$dir" AC_MSG_NOTICE([HDF5 found in $HDFDIR]) ], [ + AC_MSG_NOTICE([libhdf5 not found at $dir/lib]) AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$dir/include||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath,$dir/lib||g"`]) HDF5_OK=no ]) ], [ + AC_MSG_NOTICE([hdf5.h not found at $dir/include]) AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$dir/include||g"`]) AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$dir/lib||g; s|-Wl,-rpath,$dir/lib||g"`]) HDF5_OK=no From be60c4471608838ce13e69e5958fab185212901c Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 5 Sep 2025 23:31:48 +0100 Subject: [PATCH 233/251] Fail configuration when the explicit path specified is invalid --- configure.ac | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index d1bde56..76c92e6 100644 --- a/configure.ac +++ b/configure.ac @@ -37,16 +37,10 @@ AS_IF([test -n "$HDFDIR"], [ AC_DEFINE([HAVE_HDF5], [1], [Define if HDF5 is available]) HDF5_OK=yes ], [ - AC_MSG_NOTICE([libhdf5 not found at $HDFDIR/lib]) - AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HDFDIR/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$HDFDIR/lib||g"`]) - HDF5_OK=no + AC_MSG_ERROR([libhdf5 not found at $HDFDIR/lib]) ]) ], [ - AC_MSG_NOTICE([hdf5.h not found at $HDFDIR/include]) - AS_VAR_SET([CPPFLAGS], [`echo "$CPPFLAGS" | sed "s|-I$HDFDIR/include||g"`]) - AS_VAR_SET([LDFLAGS], [`echo "$LDFLAGS" | sed "s|-L$HDFDIR/lib||g"`]) - HDF5_OK=no + AC_MSG_ERROR([hdf5.h not found at $HDFDIR/include]) ]) ]) From e27eafb6456e0c41969e2901f52e5d83cf233b1f Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 5 Sep 2025 23:32:56 +0100 Subject: [PATCH 234/251] Remove redundant AC message --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 76c92e6..935950c 100644 --- a/configure.ac +++ b/configure.ac @@ -63,7 +63,6 @@ AS_IF([test "x$HDF5_OK" != xyes], [ ]) if test "x$HDF5_OK" != xyes; then - AC_MSG_NOTICE([--with-hdf5 not provided, checking common HDF5 environment variables...]) for var in HDF5_ROOT HDF5_HOME HDF5_DIR; do eval dir=\$$var if test -n "$dir"; then From 5b2b7343628cf5bc30c7c77f633dd707c6695303 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 5 Sep 2025 23:33:49 +0100 Subject: [PATCH 235/251] Provide guidance for users with information about honoured paths --- configure.ac | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 935950c..98a7f42 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,8 @@ AC_ARG_ENABLE([asan], # --- Check for HDF5 --- AC_ARG_WITH([hdf5], - [AS_HELP_STRING([--with-hdf5=PATH], [Path to HDF5 installation])], + [AS_HELP_STRING([--with-hdf5=PATH], + [Path to HDF5 installation. If not specified, searches in order: system paths, $HDF5_ROOT, $HDF5_HOME, $HDF5_DIR])], [HDFDIR="$withval"], []) @@ -94,7 +95,7 @@ if test "x$HDF5_OK" != xyes; then fi AS_IF([test "x$HDF5_OK" != xyes], [ - AC_MSG_ERROR([HDF5 not found]) + AC_MSG_ERROR([HDF5 not found. Use --with-hdf5=/path or set HDF5_ROOT, HDF5_HOME, or HDF5_DIR]) ]) # ---------------- Compression Option ---------------- From e958ddb68802988e52ffb5073926120d84a54179 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 5 Sep 2025 23:34:22 +0100 Subject: [PATCH 236/251] Add summary about where HDF5 is found for clarity --- configure.ac | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/configure.ac b/configure.ac index 98a7f42..b497bea 100644 --- a/configure.ac +++ b/configure.ac @@ -212,3 +212,12 @@ AS_IF([test "x$asan_build" = "xyes"], [ AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT + +# --- Configuration Summary --- +AS_IF([test "x$HDF5_OK" = xyes], [ + AS_IF([test -n "$HDFDIR"], [ + AC_MSG_NOTICE([HDF5 library found at: $HDFDIR]) + ], [ + AC_MSG_NOTICE([HDF5 library found in system paths]) + ]) +]) From 21dc1a1bb087e7b72eccdc0e0a6628d570cef208 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 5 Sep 2025 23:35:04 +0100 Subject: [PATCH 237/251] Be more specific about the discovery of HDF5 library --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d37fe57..eea4de2 100644 --- a/README.md +++ b/README.md @@ -88,9 +88,13 @@ The configure script supports several options: ##### HDF5 Location -- `--with-hdf5=/path/to/hdf5` -- It also recognises the environment variables `HDF5_ROOT`, `HDF5_HOME` -and `HDF5_DIR` +- `--with-hdf5=/path/to/hdf5`: Specify HDF5 installation path +- If not specified, the configure script searches for HDF5 in the following +order: + 1. System paths (standard locations) + 2. `$HDF5_ROOT` + 3. `$HDF5_HOME` + 4. `$HDF5_DIR` ##### Compression Support From 1c672700171fa823fb611fdd4536074536a9839f Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Fri, 5 Sep 2025 23:45:45 +0100 Subject: [PATCH 238/251] Add initial test script for building with Autotool for C --- tests/test_build/test_build_c.sh | 338 +++++++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100755 tests/test_build/test_build_c.sh diff --git a/tests/test_build/test_build_c.sh b/tests/test_build/test_build_c.sh new file mode 100755 index 0000000..c5c1718 --- /dev/null +++ b/tests/test_build/test_build_c.sh @@ -0,0 +1,338 @@ +#!/usr/bin/env bash +set -euo pipefail + +# constants +readonly script_dir="$(dirname "$(readlink -f "$0")")" +readonly project_root="$(cd "$script_dir/../.." && pwd)" +readonly log_dir="$script_dir/logs" + +# version requirements +readonly min_gcc_version=7 +readonly min_autoconf_major=2 +readonly min_autoconf_minor=64 + +total_tests=0 +passed_tests=0 +skipped_tests=0 +failed_tests=0 +hdf5_test_path="${HDF5_TEST_PATH:-}" +test_filter="all" + +cleanup() { + cd "$project_root" 2>/dev/null || true + if [[ -f Makefile ]]; then + make distclean >/dev/null 2>&1 || true + fi +} + +# register cleanup on exit +trap cleanup EXIT + +check_prerequisites() { + local errors=0 + + # check gcc + if ! command -v gcc >/dev/null 2>&1; then + echo "ERROR: gcc not found" + errors=$((errors + 1)) + else + local gcc_version + gcc_version=$(gcc -dumpversion | cut -d. -f1) + if [[ "$gcc_version" -lt $min_gcc_version ]]; then + echo "ERROR: gcc version $gcc_version < $min_gcc_version" + errors=$((errors + 1)) + fi + fi + + # check autoconf + if ! command -v autoconf >/dev/null 2>&1; then + echo "ERROR: autoconf not found" + errors=$((errors + 1)) + else + local autoconf_version + autoconf_version=$(autoconf --version | head -n1 | grep -oE '[0-9]+\.[0-9]+' | head -n1) + local major minor + IFS='.' read -r major minor <<< "$autoconf_version" + if [[ "$major" -eq $min_autoconf_major && "$minor" -lt $min_autoconf_minor ]]; then + echo "ERROR: autoconf version $autoconf_version < $min_autoconf_major.$min_autoconf_minor" + errors=$((errors + 1)) + fi + fi + + # check automake + if ! command -v automake >/dev/null 2>&1; then + echo "ERROR: automake not found" + errors=$((errors + 1)) + fi + + # no error should return exit code 0 to indicate success + return "$errors" +} + +# check if test should be run based on filter +should_run_test() { + local test_name="$1" + local filter="$2" + [[ "$filter" == "all" ]] || [[ "$filter" == "$test_name" ]] +} + +# run test in an isolated environment +run_isolated_test() { + local test_name="$1" + local configure_cmd="$2" + local env_setup="${3:-}" + + total_tests=$((total_tests + 1)) + echo -n "Test: $test_name... " + + # run in subshell for complete isolation + if ( + # clear all HDF5 env vars first + unset HDF5_ROOT HDF5_HOME HDF5_DIR + # apply test-specific environment if provided + if [[ -n "$env_setup" ]]; then + # parse space-separated var=value pairs + local -a env_pairs + IFS=' ' read -ra env_pairs <<< "$env_setup" + for pair in "${env_pairs[@]}"; do + # strip 'export ' if present + pair="${pair#export }" + # only export valid var=value pairs + if [[ "$pair" == *=* ]]; then + export "$pair" + fi + done + fi + # run the actual test + run_test_internal "$test_name" "$configure_cmd" + ); then + passed_tests=$((passed_tests + 1)) + else + failed_tests=$((failed_tests + 1)) + fi +} + +# actual test runner +run_test_internal() { + local test_name="$1" + local configure_cmd="$2" + local log_file="$log_dir/${test_name}.log" + + # clean previous build + cleanup + + # parse the command into an array + local -a cmd_array + IFS=' ' read -ra cmd_array <<< "$configure_cmd" + + # run configure (from an array of arguments) + if ! (cd "$project_root" && "${cmd_array[@]}" >>"$log_file" 2>&1); then + # attempt to extract the actual error message + local error_line=$(grep -E "error:|not found at" "$log_file" | tail -1 | sed 's/^configure: //') + if [[ -n "$error_line" ]]; then + echo "FAIL ($error_line)" + else + echo "FAIL (configure)" + fi + return 1 + fi + + # make + if ! (cd "$project_root" && make >>"$log_file" 2>&1); then + # attempt to extract make error + local error_line=$(grep -E "^make.*Error|error:" "$log_file" | tail -1 | head -c 60) + if [[ -n "$error_line" ]]; then + echo "FAIL (make: $error_line...)" + else + echo "FAIL (make)" + fi + return 1 + fi + + # test executable + local mib2h5="$project_root/src/mib2h5" + if [[ ! -f "$mib2h5" ]]; then + echo "FAIL (executable mib2h5 not found)" + return 1 + fi + + # determine hdf5 library path for LD_LIBRARY_PATH + local hdf5_lib="" + if [[ -n "${HDF5_ROOT:-}" ]]; then + hdf5_lib="$HDF5_ROOT" + elif [[ -n "${HDF5_HOME:-}" ]]; then + hdf5_lib="$HDF5_HOME" + elif [[ -n "${HDF5_DIR:-}" ]]; then + hdf5_lib="$HDF5_DIR" + elif [[ -n "$hdf5_test_path" ]] && [[ "$test_name" == "explicit_path" ]]; then + hdf5_lib="$hdf5_test_path" + fi + + local ld_path="" + if [[ -n "$hdf5_lib" ]]; then + ld_path="LD_LIBRARY_PATH=$hdf5_lib/lib:${LD_LIBRARY_PATH:-}" + fi + + # test basic commands + if ! (cd "$project_root" && env "$ld_path" "$mib2h5" --version >>"$log_file" 2>&1); then + echo "FAIL (--version)" + return 1 + fi + + if ! (cd "$project_root" && env "$ld_path" "$mib2h5" --help >>"$log_file" 2>&1); then + echo "FAIL (--help)" + return 1 + fi + + echo "PASS" + return 0 +} + + +main() { + # parse arguments + case "${1:-}" in + --clean) + echo "Cleaning build artefacts..." + cleanup + rm -rf "$log_dir" + echo "Done" + exit 0 + ;; + --list) + echo "Available tests:" + echo " system - Test with system HDF5 installation" + echo " explicit - Test with explicit --with-hdf5 path (requires HDF5_TEST_PATH)" + echo " hdf5_root - Test with HDF5_ROOT environment variable" + echo " hdf5_home - Test with HDF5_HOME environment variable" + echo " hdf5_dir - Test with HDF5_DIR environment variable" + echo "" + echo "Usage:" + echo " $0 # Run all tests" + echo " $0 --only TEST # Run specific test" + echo " $0 --list # Show this list" + echo " $0 --clean # Clean build artefacts" + exit 0 + ;; + --only) + if [[ -z "${2:-}" ]]; then + echo "Error: --only requires a test name" + echo "Use --list to see available tests" + exit 1 + fi + test_filter="$2" + ;; + *) + if [[ -n "${1:-}" ]]; then + echo "Unknown option: $1" + echo "Use --list to see available options" + exit 1 + fi + ;; + esac + + echo "=== C Build Tests ===" + if [[ "$test_filter" != "all" ]]; then + echo "Running only: $test_filter" + fi + echo + + # check prerequisites + echo -n "Prerequisites check... " + if check_prerequisites >/dev/null 2>&1; then + echo "OK" + else + echo "FAIL" + # re-run to show stdout + check_prerequisites + exit 1 + fi + echo + + # create log directory + mkdir -p "$log_dir" + + # run autoreconf once + echo -n "Running autoreconf -i... " + if (cd "$project_root" && autoreconf -i >/dev/null 2>&1); then + echo "OK" + else + echo "FAIL" + exit 1 + fi + echo + + # test 1: system hdf5 + if should_run_test "system" "$test_filter"; then + run_isolated_test "system_hdf5" "./configure" "" + fi + + # test 2: explicit path + if should_run_test "explicit" "$test_filter"; then + if [[ -n "$hdf5_test_path" ]]; then + run_isolated_test "explicit_path" "./configure --with-hdf5=$hdf5_test_path" "" + else + skipped_tests=$((skipped_tests + 1)) + echo "Test: explicit_path... SKIP (set HDF5_TEST_PATH to test)" + fi + fi + + # test 3: hdf5_root environment variable + if should_run_test "hdf5_root" "$test_filter"; then + if [[ -n "${HDF5_ROOT:-}" ]]; then + run_isolated_test "hdf5_root" "./configure" "HDF5_ROOT=$HDF5_ROOT" || true + else + skipped_tests=$((skipped_tests + 1)) + echo "Test: hdf5_root... SKIP (HDF5_ROOT not set)" + fi + fi + + # test 4: hdf5_home environment variable + if should_run_test "hdf5_home" "$test_filter"; then + if [[ -n "${HDF5_HOME:-}" ]]; then + run_isolated_test "hdf5_home" "./configure" "HDF5_HOME=$HDF5_HOME" || true + else + skipped_tests=$((skipped_tests + 1)) + echo "Test: hdf5_home... SKIP (HDF5_HOME not set)" + fi + fi + + # test 5: hdf5_dir environment variable + if should_run_test "hdf5_dir" "$test_filter"; then + if [[ -n "${HDF5_DIR:-}" ]]; then + run_isolated_test "hdf5_dir" "./configure" "HDF5_DIR=$HDF5_DIR" || true + else + skipped_tests=$((skipped_tests + 1)) + echo "Test: hdf5_dir... SKIP (HDF5_DIR not set)" + fi + fi + + # summary + echo + + # handle case where no tests ran + if [[ $total_tests -eq 0 ]] && [[ $skipped_tests -gt 0 ]]; then + echo "Tests run: 0, Skipped: $skipped_tests" + echo "No tests were run. Check --list for available tests." + exit 0 + fi + + # normal summary + echo "Tests: $passed_tests/$total_tests passed" + if [[ $skipped_tests -gt 0 ]]; then + echo "Skipped: $skipped_tests" + fi + + if [[ $failed_tests -eq 0 ]]; then + if [[ $total_tests -gt 0 ]]; then + echo "All tests passed!" + fi + exit 0 + else + echo "Failed: $failed_tests" + echo "Check logs in: $log_dir" + exit 1 + fi +} + +main "$@" From 1023357d7fef7d3647f2705000c1ddc991b26260 Mon Sep 17 00:00:00 2001 From: Timothy Poon Date: Sat, 13 Sep 2025 11:26:21 +0100 Subject: [PATCH 239/251] Add initial GH action to test building with autotools from C source --- .github/workflows/test-build-c.yml | 190 +++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 .github/workflows/test-build-c.yml diff --git a/.github/workflows/test-build-c.yml b/.github/workflows/test-build-c.yml new file mode 100644 index 0000000..1308b81 --- /dev/null +++ b/.github/workflows/test-build-c.yml @@ -0,0 +1,190 @@ +name: C Build Tests + +on: + push: + branches: [main, dev] + pull_request: + workflow_dispatch: + +jobs: + # build different hdf5 artefacts + build-hdf5: + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + matrix: + include: + - name: system + prefix: /usr/local + artefact-name: hdf5-system + - name: custom + prefix: /opt/hdf5 + artefact-name: hdf5-custom + container: gcc:7 + name: Build HDF5 - ${{ matrix.name }} + steps: + - name: Install build dependencies + run: apt update && apt install -y wget + + - name: Cache HDF5 build + id: cache-hdf5 + uses: actions/cache@v4 + with: + path: /tmp/${{ matrix.artefact-name }} + key: hdf5-1.14.6-${{ matrix.name }}-gcc7-${{ runner.os }}-v1 + restore-keys: | + hdf5-1.14.6-${{ matrix.name }}-gcc7-${{ runner.os }}- + hdf5-1.14.6-${{ matrix.name }}-gcc7- + + - name: Download and build HDF5 + if: steps.cache-hdf5.outputs.cache-hit != 'true' + run: | + # use HDF5 1.14.x + wget https://github.com/HDFGroup/hdf5/releases/download/hdf5_1.14.6/hdf5-1.14.6.tar.gz + tar -xzf hdf5-1.14.6.tar.gz + cd hdf5-1.14.6 + + # configure for specified prefix + ./configure --prefix=${{ matrix.prefix }} + make -j$(nproc) + + # staged for artefact + make install DESTDIR=/tmp/${{ matrix.artefact-name }} + + - name: Create tarball artefact + run: | + cd /tmp/${{ matrix.artefact-name }} + tar -czf /tmp/${{ matrix.artefact-name }}.tar.gz . + + - name: Upload HDF5 artefact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artefact-name }} + path: /tmp/${{ matrix.artefact-name }}.tar.gz + retention-days: 7 + compression-level: 0 + + # test gcc 7-14 + test-gcc-versions: + needs: build-hdf5 + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + gcc-version: [7, 8, 9, 10, 11, 12, 13, 14] + container: gcc:${{ matrix.gcc-version }} + name: GCC ${{ matrix.gcc-version }} - system-wide installation + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Download HDF5 system artefact + uses: actions/download-artifact@v4 + with: + name: hdf5-system + + - name: Install HDF5 system-wide + run: | + tar -xzf hdf5-system.tar.gz -C / + ldconfig + + - name: Install build dependencies + run: | + apt update + apt install -y autoconf automake libtool pkg-config + + - name: Generate configure script + run: autoreconf -i + + - name: Run build test + run: | + ./tests/test_build/test_build_c.sh --only system + + - name: Upload test logs on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: logs-gcc-${{ matrix.gcc-version }}-system + path: tests/test_build/logs/ + retention-days: 7 + + # test different methods of specifying HDF5 + test-hdf5-methods: + needs: build-hdf5 + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + include: + # system-wide + - method: system + artefact: hdf5-system + test-name: system + setup: "" + lib-path: "" + description: "system-wide HDF5 at /usr/local" + + # explicit path + - method: explicit + artefact: hdf5-custom + test-name: explicit + setup: "export HDF5_TEST_PATH=/opt/hdf5" + lib-path: /opt/hdf5/lib + description: "explicit --with-hdf5=/opt/hdf5" + + # via environment variable + - method: env_var + artefact: hdf5-custom + test-name: hdf5_root + setup: "export HDF5_ROOT=/opt/hdf5" + lib-path: /opt/hdf5/lib + description: "environment variable HDF5_ROOT" + + container: gcc:11 + name: HDF5 ${{ matrix.method }} + env: + LD_LIBRARY_PATH: ${{ matrix.lib-path }} + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Download HDF5 artefact + uses: actions/download-artifact@v4 + with: + name: ${{ matrix.artefact }} + + - name: Install HDF5 + run: | + echo "Installing HDF5 for: ${{ matrix.description }}" + tar -xzf ${{ matrix.artefact }}.tar.gz -C / + # update library cache for system-wide installation + if [ "${{ matrix.method }}" = "system" ]; then + ldconfig + fi + + - name: Install build dependencies + run: | + apt update + apt install -y autoconf automake libtool pkg-config + + - name: Generate configure script + run: autoreconf -i + + - name: Run build test + run: | + # set test-specific environment + ${{ matrix.setup }} + + # run test + echo "Testing: ${{ matrix.description }}" + ./tests/test_build/test_build_c.sh --only ${{ matrix.test-name }} + + - name: Upload test logs on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: logs-hdf5-${{ matrix.method }} + path: tests/test_build/logs/ + retention-days: 7 From 1c0b497c7fe6d5260605d87856f4ede16162b513 Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 13 Sep 2025 12:28:17 +0100 Subject: [PATCH 240/251] Use apt-get in container script --- .github/workflows/test-build-c.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-build-c.yml b/.github/workflows/test-build-c.yml index 1308b81..9c21f2f 100644 --- a/.github/workflows/test-build-c.yml +++ b/.github/workflows/test-build-c.yml @@ -24,7 +24,7 @@ jobs: name: Build HDF5 - ${{ matrix.name }} steps: - name: Install build dependencies - run: apt update && apt install -y wget + run: apt-get update && apt-get install -y wget - name: Cache HDF5 build id: cache-hdf5 @@ -91,8 +91,8 @@ jobs: - name: Install build dependencies run: | - apt update - apt install -y autoconf automake libtool pkg-config + apt-get update + apt-get install -y autoconf automake libtool pkg-config - name: Generate configure script run: autoreconf -i @@ -166,8 +166,8 @@ jobs: - name: Install build dependencies run: | - apt update - apt install -y autoconf automake libtool pkg-config + apt-get update + apt-get install -y autoconf automake libtool pkg-config - name: Generate configure script run: autoreconf -i From d0150b4b0d6d9078f629e8a8bcdda46bd1a45b3e Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 13 Sep 2025 12:39:15 +0100 Subject: [PATCH 241/251] Add sudo for apt-get --- .github/workflows/test-build-c.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-build-c.yml b/.github/workflows/test-build-c.yml index 9c21f2f..e1b5628 100644 --- a/.github/workflows/test-build-c.yml +++ b/.github/workflows/test-build-c.yml @@ -24,7 +24,7 @@ jobs: name: Build HDF5 - ${{ matrix.name }} steps: - name: Install build dependencies - run: apt-get update && apt-get install -y wget + run: sudo apt-get update && sudo apt-get install -y wget - name: Cache HDF5 build id: cache-hdf5 @@ -91,8 +91,8 @@ jobs: - name: Install build dependencies run: | - apt-get update - apt-get install -y autoconf automake libtool pkg-config + sudo apt-get update + sudo apt-get install -y autoconf automake libtool pkg-config - name: Generate configure script run: autoreconf -i @@ -166,8 +166,8 @@ jobs: - name: Install build dependencies run: | - apt-get update - apt-get install -y autoconf automake libtool pkg-config + sudo apt-get update + sudo apt-get install -y autoconf automake libtool pkg-config - name: Generate configure script run: autoreconf -i From 6f601dcd29dc2cc8ed585faf9cb7f434b6340b30 Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 13 Sep 2025 12:43:48 +0100 Subject: [PATCH 242/251] Format apt-get update and install as two lines --- .github/workflows/test-build-c.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-build-c.yml b/.github/workflows/test-build-c.yml index e1b5628..3f715f4 100644 --- a/.github/workflows/test-build-c.yml +++ b/.github/workflows/test-build-c.yml @@ -24,7 +24,9 @@ jobs: name: Build HDF5 - ${{ matrix.name }} steps: - name: Install build dependencies - run: sudo apt-get update && sudo apt-get install -y wget + run: | + sudo apt-get update + sudo apt-get install -y wget - name: Cache HDF5 build id: cache-hdf5 From 72ecf6328e4cba9c3174199ae2cb72a065ecd886 Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 13 Sep 2025 13:13:29 +0100 Subject: [PATCH 243/251] Remove sudo in Docker image --- .github/workflows/test-build-c.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-build-c.yml b/.github/workflows/test-build-c.yml index 3f715f4..801e202 100644 --- a/.github/workflows/test-build-c.yml +++ b/.github/workflows/test-build-c.yml @@ -25,8 +25,8 @@ jobs: steps: - name: Install build dependencies run: | - sudo apt-get update - sudo apt-get install -y wget + apt-get update + apt-get install -y wget - name: Cache HDF5 build id: cache-hdf5 @@ -93,8 +93,8 @@ jobs: - name: Install build dependencies run: | - sudo apt-get update - sudo apt-get install -y autoconf automake libtool pkg-config + apt-get update + apt-get install -y autoconf automake libtool pkg-config - name: Generate configure script run: autoreconf -i @@ -168,8 +168,8 @@ jobs: - name: Install build dependencies run: | - sudo apt-get update - sudo apt-get install -y autoconf automake libtool pkg-config + apt-get update + apt-get install -y autoconf automake libtool pkg-config - name: Generate configure script run: autoreconf -i From f85866954d69d65c8d7132483ed225afd4edaca8 Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 13 Sep 2025 13:40:08 +0100 Subject: [PATCH 244/251] Use archive repositories for gcc <= 10 --- .github/workflows/test-build-c.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/test-build-c.yml b/.github/workflows/test-build-c.yml index 801e202..f1be3e1 100644 --- a/.github/workflows/test-build-c.yml +++ b/.github/workflows/test-build-c.yml @@ -23,6 +23,12 @@ jobs: container: gcc:7 name: Build HDF5 - ${{ matrix.name }} steps: + - name: Use archive repositories for Debian Buster + run: | + sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list + sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list + sed -i '/buster-updates/d' /etc/apt/sources.list + - name: Install build dependencies run: | apt-get update @@ -91,6 +97,14 @@ jobs: tar -xzf hdf5-system.tar.gz -C / ldconfig + - name: Use archive repositories for Debian Buster + if: matrix.gcc-version <= 10 + run: | + # gcc 7-10 use debian buster which reached EOL + sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list + sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list + sed -i '/buster-updates/d' /etc/apt/sources.list + - name: Install build dependencies run: | apt-get update From d33ef8f79c0460a97e172f09390ce0a2dfce59de Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 13 Sep 2025 14:22:32 +0100 Subject: [PATCH 245/251] Avoid passing empty string to env --- tests/test_build/test_build_c.sh | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/tests/test_build/test_build_c.sh b/tests/test_build/test_build_c.sh index c5c1718..66a4ff4 100755 --- a/tests/test_build/test_build_c.sh +++ b/tests/test_build/test_build_c.sh @@ -174,14 +174,28 @@ run_test_internal() { fi # test basic commands - if ! (cd "$project_root" && env "$ld_path" "$mib2h5" --version >>"$log_file" 2>&1); then - echo "FAIL (--version)" - return 1 - fi + if [[ -n "$ld_path" ]]; then + # use env when ld_path is set + if ! (cd "$project_root" && env "$ld_path" "$mib2h5" --version >>"$log_file" 2>&1); then + echo "FAIL (--version)" + return 1 + fi - if ! (cd "$project_root" && env "$ld_path" "$mib2h5" --help >>"$log_file" 2>&1); then - echo "FAIL (--help)" - return 1 + if ! (cd "$project_root" && env "$ld_path" "$mib2h5" --help >>"$log_file" 2>&1); then + echo "FAIL (--help)" + return 1 + fi + else + # run directly when ld_path is empty (system-wide installation) + if ! (cd "$project_root" && "$mib2h5" --version >>"$log_file" 2>&1); then + echo "FAIL (--version)" + return 1 + fi + + if ! (cd "$project_root" && "$mib2h5" --help >>"$log_file" 2>&1); then + echo "FAIL (--help)" + return 1 + fi fi echo "PASS" From 761858b5ee44946795ed7f540bbcc49c8fee69e8 Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 13 Sep 2025 14:40:59 +0100 Subject: [PATCH 246/251] Fix gcc docker version with buster --- .github/workflows/test-build-c.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-build-c.yml b/.github/workflows/test-build-c.yml index f1be3e1..38a671f 100644 --- a/.github/workflows/test-build-c.yml +++ b/.github/workflows/test-build-c.yml @@ -98,9 +98,9 @@ jobs: ldconfig - name: Use archive repositories for Debian Buster - if: matrix.gcc-version <= 10 + if: matrix.gcc-version == 7 || matrix.gcc-version == 8 run: | - # gcc 7-10 use debian buster which reached EOL + # gcc 7, 8 use debian buster which reached EOL sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list sed -i '/buster-updates/d' /etc/apt/sources.list From 5a332b063d07499237bbc6aa6b0ce94543189c7c Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:23:07 +0100 Subject: [PATCH 247/251] Fix missed method call --- python/src/mib2h5/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/mib2h5/cli.py b/python/src/mib2h5/cli.py index 881b008..6a79cbd 100644 --- a/python/src/mib2h5/cli.py +++ b/python/src/mib2h5/cli.py @@ -128,7 +128,7 @@ def main() -> int: # validate input files exist missing_files = [] for filepath in args.input_files: - if not Path(filepath).exists: + if not Path(filepath).exists(): missing_files.append(filepath) if missing_files: From 0d175d724c6ab58defd9c8a33412079e3ae9f2d2 Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 20 Sep 2025 00:25:24 +0100 Subject: [PATCH 248/251] Add initial test script for building the Python wrapper --- tests/test_build/test_build_python.sh | 338 ++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100755 tests/test_build/test_build_python.sh diff --git a/tests/test_build/test_build_python.sh b/tests/test_build/test_build_python.sh new file mode 100755 index 0000000..52857ef --- /dev/null +++ b/tests/test_build/test_build_python.sh @@ -0,0 +1,338 @@ +#!/usr/bin/env bash +set -euo pipefail + +# constants +readonly script_dir="$(dirname "$(readlink -f "$0")")" +readonly project_root="$(cd "$script_dir/../.." && pwd)" +readonly python_dir="$project_root/python" +readonly log_dir="$script_dir/logs" + +# version requirements +readonly min_python_major=3 +readonly min_python_minor=10 + +total_tests=0 +passed_tests=0 +failed_tests=0 +skipped_tests=0 +test_filter="all" + +cleanup() { + cd "$project_root" 2>/dev/null || true + if [[ -f Makefile ]]; then + make distclean >/dev/null 2>&1 || true + fi + + # clean python build artefacts + rm -rf "$python_dir/build" 2>/dev/null || true + rm -rf "$python_dir/dist" 2>/dev/null || true + rm -rf "$python_dir/src/mib2h5.egg-info" 2>/dev/null || true + rm -rf "$python_dir/src/mib2h5/_wrapper.c" 2>/dev/null || true + rm -rf "$python_dir/src/mib2h5/_wrapper."*.so 2>/dev/null || true + rm -rf "$python_dir/__pycache__" 2>/dev/null || true + rm -rf "$python_dir/src/mib2h5/__pycache__" 2>/dev/null || true + + # clean pipx installation + if command -v pipx >/dev/null 2>&1; then + pipx uninstall mib2h5 >/dev/null 2>&1 || true + fi +} + +# register cleanup on exit +trap cleanup EXIT + +check_prerequisites() { + local errors=0 + + # check hdf5_root is set + if [[ -z "${HDF5_ROOT:-}" ]]; then + echo "ERROR: HDF5_ROOT environment variable not set" + errors=$((errors + 1)) + elif [[ ! -d "${HDF5_ROOT}" ]]; then + echo "ERROR: HDF5_ROOT directory does not exist: ${HDF5_ROOT}" + errors=$((errors + 1)) + fi + + # check python version + if ! command -v python3 >/dev/null 2>&1; then + echo "ERROR: python3 not found" + errors=$((errors + 1)) + else + local python_version + python_version=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")') + local major minor + IFS='.' read -r major minor <<< "$python_version" + if [[ "$major" -lt $min_python_major ]] || [[ "$major" -eq $min_python_major && "$minor" -lt $min_python_minor ]]; then + echo "ERROR: Python $min_python_major.$min_python_minor+ required, found $python_version" + errors=$((errors + 1)) + fi + fi + + return "$errors" +} + +# check if test should be run based on filter +should_run_test() { + local test_name="$1" + local filter="$2" + [[ "$filter" == "all" ]] || [[ "$filter" == "$test_name" ]] +} + +# run test in an isolated environment +run_isolated_test() { + local test_name="$1" + local install_method="$2" + + total_tests=$((total_tests + 1)) + echo -n "Test: $test_name... " + + # run in subshell for complete isolation + if ( + # clear environment variables that might interfere + unset PYTHONPATH + unset PIP_CONFIG_FILE + unset PIP_CACHE_DIR + + # set required environment + export LD_LIBRARY_PATH="${HDF5_ROOT}/lib:${LD_LIBRARY_PATH:-}" + + # run the actual test + run_test_internal "$test_name" "$install_method" + ); then + passed_tests=$((passed_tests + 1)) + else + failed_tests=$((failed_tests + 1)) + fi +} + +# actual test runner +run_test_internal() { + local test_name="$1" + local install_method="$2" + local log_file="${log_dir}/${test_name}.log" + + # create temp directory for virtual environment + local temp_dir + temp_dir=$(mktemp -d /tmp/mib2h5_test_XXXXXX) + local venv_dir="$temp_dir/venv" + + # ensure temp directory cleanup + trap "rm -rf '$temp_dir'" RETURN + + # clean previous build + cleanup + + # create virtual environment + if ! python3 -m venv "$venv_dir" >>"$log_file" 2>&1; then + echo "FAIL (venv creation)" + return 1 + fi + + # use venv's pip directly (no need to activate in subshell) + local pip_cmd="$venv_dir/bin/pip" + local python_cmd="$venv_dir/bin/python" + + # upgrade pip and install build dependencies + if ! "$pip_cmd" install --upgrade pip 'setuptools>=77.0' wheel 'cython>=3' >>"$log_file" 2>&1; then + echo "FAIL (pip dependencies)" + return 1 + fi + + # change to python directory + cd "$python_dir" + + # install package based on method + case "$install_method" in + "standard") + if ! "$pip_cmd" install . >>"$log_file" 2>&1; then + local error_line + error_line=$(grep -E "error:|ERROR:|FAILED" "$log_file" | tail -1 | head -c 60) + if [[ -n "$error_line" ]]; then + echo "FAIL (install: $error_line...)" + else + echo "FAIL (install)" + fi + return 1 + fi + ;; + "editable") + if ! "$pip_cmd" install -e . >>"$log_file" 2>&1; then + local error_line + error_line=$(grep -E "error:|ERROR:|FAILED" "$log_file" | tail -1 | head -c 60) + if [[ -n "$error_line" ]]; then + echo "FAIL (editable install: $error_line...)" + else + echo "FAIL (editable install)" + fi + return 1 + fi + ;; + "pipx") + # for pipx, we use the global pipx command + export PIPX_DEFAULT_PYTHON=$(which python3) + if ! pipx install . --verbose >>"$log_file" 2>&1; then + local error_line + error_line=$(grep -E "error:|ERROR:|FAILED" "$log_file" | tail -1 | head -c 60) + if [[ -n "$error_line" ]]; then + echo "FAIL (pipx install: $error_line...)" + else + echo "FAIL (pipx install)" + fi + return 1 + fi + ;; + *) + echo "FAIL (unknown install method)" + return 1 + ;; + esac + + # test cli version + local mib2h5_cmd + if [[ "$install_method" == "pipx" ]]; then + mib2h5_cmd="mib2h5" + else + mib2h5_cmd="$venv_dir/bin/mib2h5" + fi + + if ! "$mib2h5_cmd" --version >>"$log_file" 2>&1; then + echo "FAIL (--version)" + return 1 + fi + + # test cli help + if ! "$mib2h5_cmd" --help >>"$log_file" 2>&1; then + echo "FAIL (--help)" + return 1 + fi + + # test python import (skip for pipx as it uses isolated environment) + if [[ "$install_method" != "pipx" ]]; then + if ! "$python_cmd" -c "import mib2h5; print('Import successful')" >>"$log_file" 2>&1; then + echo "FAIL (import)" + return 1 + fi + fi + + # cleanup pipx installation + if [[ "$install_method" == "pipx" ]]; then + pipx uninstall mib2h5 >>"$log_file" 2>&1 || true + fi + + echo "PASS" + return 0 +} + +main() { + # parse arguments + case "${1:-}" in + --clean) + echo "Cleaning build artefacts..." + cleanup + rm -rf "$log_dir" + echo "Done" + exit 0 + ;; + --list) + echo "Require setting HDF5_ROOT to the HDF5 installation" + echo + echo "Available tests:" + echo " standard - Standard pip install" + echo " editable - Editable/development install" + echo " pipx - pipx install" + echo "" + echo "Usage:" + echo " $0 # Run all tests" + echo " $0 --only TEST # Run specific test" + echo " $0 --list # Show this list" + echo " $0 --clean # Clean build artefacts" + exit 0 + ;; + --only) + if [[ -z "${2:-}" ]]; then + echo "Error: --only requires a test name" + echo "Use --list to see available tests" + exit 1 + fi + test_filter="$2" + ;; + *) + if [[ -n "${1:-}" ]]; then + echo "Unknown option: $1" + echo "Use --list to see available options" + exit 1 + fi + ;; + esac + + echo "=== Python Build Tests ===" + if [[ "$test_filter" != "all" ]]; then + echo "Running only: $test_filter" + fi + echo "HDF5_ROOT: ${HDF5_ROOT:-not set}" + echo + + # check prerequisites + echo -n "Prerequisites check... " + if check_prerequisites >/dev/null 2>&1; then + echo "OK" + else + echo "FAIL" + # re-run to show stdout + check_prerequisites + exit 1 + fi + echo + + # create log directory + mkdir -p "$log_dir" + + # test 1: standard install + if should_run_test "standard" "$test_filter"; then + run_isolated_test "standard_install" "standard" + fi + + # test 2: editable install + if should_run_test "editable" "$test_filter"; then + run_isolated_test "editable_install" "editable" + fi + + # test 3: pipx install + if should_run_test "pipx" "$test_filter"; then + if command -v pipx >/dev/null 2>&1; then + run_isolated_test "pipx_install" "pipx" + else + skipped_tests=$((skipped_tests + 1)) + echo "Test: pipx_install... SKIP (pipx not found)" + fi + fi + + # summary + echo + + # handle case where no tests ran + if [[ $total_tests -eq 0 ]] && [[ $skipped_tests -gt 0 ]]; then + echo "Tests run: 0, Skipped: $skipped_tests" + echo "No tests were run. Check --list for available tests." + exit 0 + fi + + # normal summary + echo "Tests: $passed_tests/$total_tests passed" + if [[ $skipped_tests -gt 0 ]]; then + echo "Skipped: $skipped_tests" + fi + + if [[ $failed_tests -eq 0 ]]; then + if [[ $total_tests -gt 0 ]]; then + echo "All tests passed!" + fi + exit 0 + else + echo "Failed: $failed_tests" + echo "Check logs in: $log_dir" + exit 1 + fi +} + +main "$@" From 65a31d3fc6ea657af512fbaf295d6d74dcad1ade Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 27 Sep 2025 12:09:04 +0100 Subject: [PATCH 249/251] Add initial GH action for testing Python build --- .github/workflows/test-build-python.yml | 116 ++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 .github/workflows/test-build-python.yml diff --git a/.github/workflows/test-build-python.yml b/.github/workflows/test-build-python.yml new file mode 100644 index 0000000..660ab9a --- /dev/null +++ b/.github/workflows/test-build-python.yml @@ -0,0 +1,116 @@ +name: Python Build Tests + +on: + push: + branches: [main, dev] + pull_request: + +jobs: + # build hdf5 library for python tests + build-hdf5: + runs-on: ubuntu-latest + timeout-minutes: 30 + container: gcc:7 + name: Build HDF5 + steps: + - name: Cache HDF5 build + id: cache-hdf5 + uses: actions/cache@v4 + with: + path: /tmp/hdf5-python + key: hdf5-1.14.6-python-gcc7-${{ runner.os }}-v1 + restore-keys: | + hdf5-1.14.6-python-gcc7-${{ runner.os }}- + hdf5-1.14.6-python-gcc7- + + - name: Download and build HDF5 + if: steps.cache-hdf5.outputs.cache-hit != 'true' + run: | + # use archive repositories for Debian Buster + sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list + sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list + sed -i '/buster-updates/d' /etc/apt/sources.list + apt-get update && apt-get install -y wget + + # use HDF5 1.14.x + wget https://github.com/HDFGroup/hdf5/releases/download/hdf5_1.14.6/hdf5-1.14.6.tar.gz + tar -xzf hdf5-1.14.6.tar.gz + cd hdf5-1.14.6 + + # configure for /opt/hdf5 + ./configure --prefix=/opt/hdf5 + make -j$(nproc) + + # staged for artefact + make install DESTDIR=/tmp/hdf5-python + + - name: Create tarball artefact + run: | + cd /tmp/hdf5-python + tar -czf /tmp/hdf5-python.tar.gz . + + - name: Upload HDF5 artefact + uses: actions/upload-artifact@v4 + with: + name: hdf5-python + path: /tmp/hdf5-python.tar.gz + compression-level: 0 + + # test python installation methods + test-python: + needs: build-hdf5 + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + HDF5_ROOT: /opt/hdf5 + LD_LIBRARY_PATH: /opt/hdf5/lib + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + install-method: ["standard"] + include: + # add editable and pipx test for lowest-supported Python + - python-version: "3.10" + install-method: "editable" + - python-version: "3.10" + install-method: "pipx" + name: Python ${{ matrix.python-version }} - ${{ matrix.install-method }} + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y autoconf automake libtool + # install pipx only when needed + if [[ "${{ matrix.install-method }}" == "pipx" ]]; then + sudo apt-get install -y pipx + fi + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + + - name: Download HDF5 artefact + uses: actions/download-artifact@v4 + with: + name: hdf5-python + + - name: Install HDF5 + run: | + sudo tar -xzf hdf5-python.tar.gz -C / + + - name: Run build test + run: | + ./tests/test_build/test_build_python.sh --only ${{ matrix.install-method }} + + - name: Upload test logs on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: logs-py${{ matrix.python-version }}-${{ matrix.install-method }} + path: tests/test_build/logs/ + retention-days: 7 From ce4e5bfb55cc6a144e56a5c3c06b0eb82138c56c Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 27 Sep 2025 12:42:24 +0100 Subject: [PATCH 250/251] Use default retention day for hdf5 library in C test GH action (90 days) --- .github/workflows/test-build-c.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-build-c.yml b/.github/workflows/test-build-c.yml index 38a671f..80d26ec 100644 --- a/.github/workflows/test-build-c.yml +++ b/.github/workflows/test-build-c.yml @@ -69,7 +69,6 @@ jobs: with: name: ${{ matrix.artefact-name }} path: /tmp/${{ matrix.artefact-name }}.tar.gz - retention-days: 7 compression-level: 0 # test gcc 7-14 From a8500e015f3f429cf71e9706d4869d2012305faa Mon Sep 17 00:00:00 2001 From: Timothy Poon <62692924+ptim0626@users.noreply.github.com> Date: Sat, 27 Sep 2025 12:58:41 +0100 Subject: [PATCH 251/251] Only download build dependency if needed in C GH build tests --- .github/workflows/test-build-c.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test-build-c.yml b/.github/workflows/test-build-c.yml index 80d26ec..458c045 100644 --- a/.github/workflows/test-build-c.yml +++ b/.github/workflows/test-build-c.yml @@ -23,17 +23,6 @@ jobs: container: gcc:7 name: Build HDF5 - ${{ matrix.name }} steps: - - name: Use archive repositories for Debian Buster - run: | - sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list - sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list - sed -i '/buster-updates/d' /etc/apt/sources.list - - - name: Install build dependencies - run: | - apt-get update - apt-get install -y wget - - name: Cache HDF5 build id: cache-hdf5 uses: actions/cache@v4 @@ -47,6 +36,12 @@ jobs: - name: Download and build HDF5 if: steps.cache-hdf5.outputs.cache-hit != 'true' run: | + # use archive repositories for Debian Buster + sed -i 's|deb.debian.org|archive.debian.org|g' /etc/apt/sources.list + sed -i 's|security.debian.org|archive.debian.org|g' /etc/apt/sources.list + sed -i '/buster-updates/d' /etc/apt/sources.list + apt-get update && apt-get install -y wget + # use HDF5 1.14.x wget https://github.com/HDFGroup/hdf5/releases/download/hdf5_1.14.6/hdf5-1.14.6.tar.gz tar -xzf hdf5-1.14.6.tar.gz