flockaroo blogaroo
  1. Aktuelle Seite:  
  2. Startseite
  3. Uncategorised

Uncategorised

Convert Laser-Engraver to Plotter

Details
Geschrieben von: flockaroo
Kategorie: Uncategorised
Veröffentlicht: 25. September 2024
Zugriffe: 1475
  • plotter
  • engraver
  • laser
  • servo

Prototype

i had this Longer Ray5 Laser-Engraver and i always wondered how to convert it to a plotter...

longer engraver >>>
engraver   plotter

 

using a standard servo:

servo

...turned out that electronically there was not much conversion necessary because:

The Engraver is driven by a Makerbase board (ESP32 chip).

The laser is cntrolled by 5000 to 20000 Hz PWM signal.

in an undocumented setting ($33) the board can be configured to much lower PWM frequency (can either be done in webinterface or telnet connetion or serial or directly in the gcode-file)

$33=50

and 50Hz is the PWM frequency of standard servos, so i gave that a try...

however the laser is driven by 12 V and the servo only 5V, so iadded some DC-DC step down buck converter (voltage needs to be adjusted at the small potentiometer):

step down buck

added some small board and connectors the white one is the laser-connector (12V,GND,PWM) and the black one goes to the servo (GND,5V,PWM):

buck1buck2

its small enough to let it hang loose on the cables (for now).

and it worked... here a 1st test with a wildly mounted servo (bc i was impatient):

1st dirty tests just wildly mounting a servo

the servo is then driven by spindle-speed commands in G-Code (e.g. "G1 X100 Y100 S110")

info about servo:

the pwm of servo uses up to ~2200us (varies with different vendors) pulse-width (about 1/10th from full 20ms PWM cycle), so if our max spindlespeed is 1000 (preset of longer-raw5 which is 100% of PWM cycle) then only spindlespeed values up to ~110 should be used, because the servo might not be able to cope. ...i tested it and above 125 (and below ~30) the servo actually behaved weirdly and turned around all over or slowly drifted - which makes sense.

so to be safe S-values should ideally be somewhere between lets say 50 an 110 (might be different for other servos)

turned out for my servo mount the proper values were 100 just touching paper and the continuously higher pressure up until 115.

...as a followup i did some more exact calculations here:

SERVO:
servo PWM frequency 50Hz -> period = 20000 us servo pulse widths: 500..2500 us -> 0..180 deg Engraver RPM values (assuming 8 bit res - so ~0.4% clamped off on both ends -> 0.4%..99.6%): r0 0 = 0.4 % duty cycle = 80 us (t0) r1 1000 = 99.6 % duty cycle = 19920 us (t1) values: 0..1000 -> 0.4 .. 99.6 % of 20000 -> 80us..19920us RPM-val = r0+(t-t0)/(t1-t0)*(r1-r0) RPM-val for 0 deg -> 500us = 0.025 * 20000 us = (500-80)/(19920-80)*1000 = 21.17 RPM-val for 180 deg -> 2500us = 0.125 * 20000 us = (2500-80)/(19920-80)*1000 = 121.98

...so RPM-values should vary from 22 to 122 for 0..180 degree

 

Pen Holder

Finally i modelled and 3d-printed some pen holder to make proper plots.

this pen holder has the servo connected to the pen sledge by a spring, so i can control pen-pressure continuously (...my 3d-printer is not the best of its type ;-P):

3d-printed pen holder

here my 2 obj files ready for 3d-printing - click image for link to obj-file (save link as...):

penholder1  penholder holder

there's no mounting hole for the actual pen-part - i just drilled that by hand. and the spring mount was also quite improvised, just bolted it on bottom of the lower sledge and wound it through one of servo holes.

 

the 2 parts of the pen-sledge should be connected by two 8cm long 3mm bolts (glued on one side).

in principle one could also skip the spring and use a standard servo-saver for varying the pen-force (but i had none at hand...).

edit: ...new improved versions here for download (can also hold bigger 40mm servos):

big pen   pen schlitten   servoholder   

new pen/servo holder in action

Results

in action...

final plot...

final plot with varying pencil-pressure

ZX Spectrum - found my old spectrum - got carried away by some retro-coding

Details
Geschrieben von: flockaroo
Kategorie: Uncategorised
Veröffentlicht: 24. März 2024
Zugriffe: 638

...endless mountain scape, scrolling on and on and on

...so i found this old baby in a forgotten closet, and got carried away by some basic/assembly coding.

strange experience after long time only shader coding (assembly coding feels a bit like playing "sokoban" (for those who know) - just pushing around registers instead of boxes...)

dfghdfh     zx-mountains-png

Source Code:

for developing on pc i used ZXBasic,

just get the repos by: "git clone https://github.com/boriel/zxbasic.git"

and then simply compile my source with:

zxbc.py -taB zx_mountains.bas

Here's the source (ZXBasic + assembly) - forgive the wild coding style... most likely there's lots of room for improvement (...i haven't coded assembly for ages).

ZX_MOUNTAINS.BAS:

REM
REM   ZX-Mountains by flockaroo (Florian Berger) - 2024
REM
REM   License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
REM

BORDER 7
PAPER 7
INK 1
CLS

PRINT AT 21,15;"    ZX-Mountains"
PRINT AT 23,23;"flockaoo"

LET rx=25
LET ry=19
REM abs(sin)
DIM asint(63) as UBYTE => {0,12,24,37,49,61,73,85,97,108,119,130,141,151,161,170,179,188,196,204,211,217,224,229,234,239,243,246,249,251,252,253,253,253,252,251,249,246,243,239,234,229,224,217,211,204,196,188,179,170,161,151,141,130,119,108,97,85,73,61,49,37,24,12}
DIM binv8(255) as UBYTE => {0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255}

function drawRightColAsm(FCx as integer)
  REM PRINT "FCx0",FCx
  FCx=FCx+1
  ASM
  push HL
  pop BC
  ld HL,FCx
  ld (HL),C
  inc HL
  ld (HL),B
  jp data_end

;
; div8, mul8 - from here: https://tutorials.eeems.ca/Z80ASM/part4.htm
;
div8_HL_HL_D:
  push bc
Div8:                            ; this routine performs the operation HL=HL/D
  xor a                          ; clearing the upper 8 bits of AHL
  ld b,16                        ; the length of the dividend (16 bits)
Div8Loop:
  add hl,hl                      ; advancing a bit
  rla
  cp d                           ; checking if the divisor divides the digits chosen (in A)
  jp c,Div8NextBit               ; if not, advancing without subtraction
  sub d                          ; subtracting the divisor
  inc l                          ; and setting the next digit of the quotient
Div8NextBit:
  djnz Div8Loop
  pop bc
  ret

mul8_HL_H_E:
  push bc
  ld b,d
  push bc
Mul8b:                           ; this routine performs the operation HL=H*E
  ld d,0                         ; clearing D and L
  ld l,d
  ld b,8                         ; we have 8 bits
Mul8bLoop:
  add hl,hl                      ; advancing a bit
  jp nc,Mul8bSkip                ; if zero, we skip the addition (jp is used for speed)
  add hl,de                      ; adding to the product if necessary
Mul8bSkip:
  djnz Mul8bLoop
  pop bc
  ld d,b
  pop bc
  ret
  
mod8_HL_HL_D: ; ...derived from div8 above
  push bc
   ld b,e
   push bc
    push HL
     call div8_HL_HL_D
     ld H,L
     ld E,D
     call mul8_HL_H_E
    pop BC
    dec HL
    ld A,H
    neg
    ld H,A
    ld A,L
    neg
    ld L,A
    ADD HL,BC
   pop bc
   ld e,b
  pop bc
  ret

  END ASM

  H_d:
  asm
  Hi: DEFB 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
  dH: DEFB 10,10  ;=int(192/Hnum)
  dC: DEFB 20  ;=int(200/Hnum)
  dummy: DEFB 30 ; debug dummy
  XX: DEFB 0,0
  data_end:
#if 1
  end asm

  REM FIXME: port this to ASM!!
  const Hnum=5
  REM DIM H(Hnum) As UBYTE
  DIM dummy(1) as UBYTE at @H_d+19
  DIM dH(1) as Uinteger at @H_d+16
  DIM dC(1) as UBYTE at @H_d+18
  DIM H(Hnum) As UBYTE at @H_d
  dH(0) = int(192/Hnum)
  dC(0) = int(200/Hnum)

  DIM XX as uinteger = FCx*(Hnum)
  DIM Hi as uinteger
  FOR i=0 to Hnum-1
     Hi=(dH(0)>>2)*(i+2)+(dH(0)*i*i<<1)/Hnum/Hnum
     Hi=Hi*(Hnum-i)
     Hi=Hi+(asint(((XX*60 )>>8)&63)>>2)-32
     Hi=Hi+(asint(((XX*137)>>8)&63)>>3)-16
     if i=Hnum-1 then
     Hi=Hi+(asint(((XX    )   )&63)>>4)-8
     end if
     H(i)=Hi/(Hnum-i)
     XX=XX-FCx+i*11
  NEXT i

  ASM
#else
  ; WIP... above code in ASM - not working yet... :-(
    ;DIM XX as uinteger = FCx*(Hnum)
    push HL
     ld HL,Hnum
     ld B,(HL)
     ld HL,0
     sumloop:
     ADD HL,DE
     djnz sumloop
     ld HL,XX  ; store XX
     LD (HL),E
     inc HL
     LD (HL),D
    pop HL
    ;push DE   ; push  XX
    ;FOR i=0 to Hnum-1
    ld B,0
    loop_Hi:
     ;H(i)=(dH(0)>>1)+(dH(0)>>2)*i+(dH(0)*i*i<<1)/Hnum/Hnum
     ;approx:H(i)=(dH(0)>>2)*(i+2)+(dH(0)*i*i<<1)/Hnum/Hnum
     push BC
      ld HL,Hnum
      ld D,(HL)
      ld E,B
      SLA L
      ld HL,0
      sumloop2:
      ADD HL,DE
      djnz sumloop2 ; L=i*i*2, H=Hnum*Hnum
      ld D,H
      ld E,L
     pop BC
     ld HL,dH
     ld H,(HL)
     push DE
     call mul8_HL_H_E    ; dH*i*i*2
     pop DE
     call div8_HL_HL_D  ; HL=(dH(0)*i*i<<1)/Hnum/Hnum
     push HL

      push BC
       ld HL,dH
       ld C,(HL)
       SRL C
       SRL C
       inc B
       ld A,C
       sumloop3:
        add A,C
       djnz sumloop3 ; A=(dH>>2)*(i+2)
      pop BC
      ld L,A
      ld H,0
      ;ld HL,dH
      ;ld H,(HL)
      ;SRL H
      ;SRL H
      ;ld A,B
      ;add A,2
      ;ld E,A
      ;call mul8_HL_H_E
     pop DE
     ADD HL,DE          ; HL=(dH(0)>>2)*(i+2)+(dH(0)*i*i<<1)/Hnum/Hnum
     push HL
      ld HL,Hnum
      ld A,(HL)
      SUB B
     popHL
     ld E,A
     call mul8_HL_H_E   ; HL=(...)*(Hnum-i)
     push HL

      ;Hi=Hi+(sint(((XX*60 )>>8)&63)>>2)-32
      ld HL,XX
      inc HL
      ld H,(HL)  ; DE=XX>>8 (high byte only)
      ld E,60
      call mul8_HL_H_E
      ld A,H
      AND 63
      ld HL,bsin6
      ld D,0
      ld E,A
      add HL,DE
      ld A,(HL)   ;A=sint(((XX*100)>>8)&63)
      SRL A
      SRL A       ;A=sint(((XX*100)>>8)&63)>>2
      ld E,A
      ld D,0
     pop HL
     ADD HL,DE     ; +(sint(((XX*100)>>8)&63)>>2)
     ld DE,0FFE0h
     ADD HL,DE ; -32
     push HL

      ;Hi=Hi/(Hnum-i)
      ld HL,Hnum
      ld A,(HL)
      SUB B
      ld D,A
     pop HL
     call div8_HL_HL_D   ; HL=HL/(Hnum-i)
     push HL

     pop DE
     ;H(i)=Hi
     ld HL,Hi
     ld D,0
     ld E,B
     add HL,DE
     ld (HL),E   ; write to H(i)

     ;XX=XX-FCx
     ld HL,XX
     ld E,(HL)
     inc HL
     ld D,(HL)  ; DE=XX
     push DE
      ld HL,FCx
      ld E,(HL)
      inc HL
      ld D,(HL)  ; DE=FCx
     pop HL
     dec DE
     ld A,E
     xor 255
     ld E,A
     ld A,D
     xor 255
     ld D,A
     ADD HL,DE
     push HL
     pop DE
     ;ld DE, HL
     ld HL,XX  ; write back XX
     ld (HL),E
     ld (HL),D

      ;H(i)=H(i)+(int(sint(((XX*189)>>8)&63)-127)*12>>7)/(Hnum-i)
      ;if i=Hnum-1 then
      ; H(i)=H(i)+(int(sint(((XX*417)>>8)&63)-127)>>6)/(Hnum-i)
      ;end if

    ;NEXT i
    inc B
    ld A,B
    ld HL,Hnum
    cp (HL)
    jp nz,loop_Hi

#endif

  jp end_of_data
  ; 8 bit bit-mirrored
  binv8: DEFB 0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255
  ; biased sin 6 bit full period 0..255
  bsin6: DEFB 127,139,151,163,175,186,197,207,216,225,232,239,244,248,251,253,254,253,251,248,244,239,232,225,216,207,197,186,175,163,151,139,126,114,102,90,78,67,56,46,37,28,21,14,9,5,2,0,0,0,2,5,9,14,21,28,37,46,56,67,78,90,102,114
  bayer: DEFB  0, 32,  8, 40,  2, 34, 10, 42
         DEFB 48, 16, 56, 24, 50, 18, 58, 26
         DEFB 12, 44,  4, 36, 14, 46,  6, 38
         DEFB 60, 28, 52, 20, 62, 30, 54, 22
         DEFB  3, 35, 11, 43,  1, 33,  9, 41
         DEFB 51, 19, 59, 27, 49, 17, 57, 25
         DEFB 15, 47,  7, 39, 13, 45,  5, 37
         DEFB 63, 31, 55, 23, 61, 29, 53, 21
  biX7:  DEFB 0,0
  FCx:   DEFB 0,0
  Hnum:  DEFB 5
  lastmin:  DEFB 0
  DosFont8: DEFB 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 03Ch, 042h, 0A5h, 081h, 0BDh, 042h, 03Ch, 000h, 03Ch, 07Eh, 0DBh, 0FFh, 0C3h, 07Eh, 03Ch, 000h, 000h, 0EEh, 0FEh, 0FEh, 07Ch, 038h, 010h, 000h, 010h, 038h, 07Ch, 0FEh, 07Ch, 038h, 010h, 000h, 000h, 03Ch, 018h, 0FFh, 0FFh, 008h, 018h, 000h, 010h, 038h, 07Ch, 0FEh, 0FEh, 010h, 038h, 000h, 000h, 000h, 018h, 03Ch, 018h, 000h, 000h, 000h, 0FFh, 0FFh, 0E7h, 0C3h, 0E7h, 0FFh, 0FFh, 0FFh, 000h, 03Ch, 042h, 081h, 081h, 042h, 03Ch, 000h, 0FFh, 0C3h, 0BDh, 07Eh, 07Eh, 0BDh, 0C3h, 0FFh, 01Fh, 007h, 00Dh, 07Ch, 0C6h, 0C6h, 07Ch, 000h, 000h, 07Eh, 0C3h, 0C3h, 07Eh, 018h, 07Eh, 018h, 004h, 006h, 007h, 004h, 004h, 0FCh, 0F8h, 000h, 00Ch, 00Ah, 00Dh, 00Bh, 0F9h, 0F9h, 01Fh, 01Fh, 000h, 092h, 07Ch, 044h, 0C6h, 07Ch, 092h, 000h, 000h, 000h, 060h, 078h, 07Eh, 078h, 060h, 000h, 000h, 000h, 006h, 01Eh, 07Eh, 01Eh, 006h, 000h, 018h, 07Eh, 018h, 018h, 018h, 018h, 07Eh, 018h, 066h, 066h, 066h, 066h, 066h, 000h, 066h, 000h, 0FFh, 0B6h, 076h, 036h, 036h, 036h, 036h, 000h, 07Eh, 0C1h, 0DCh, 022h, 022h, 01Fh, 083h, 07Eh, 000h, 000h, 000h, 07Eh, 07Eh, 000h, 000h, 000h, 018h, 07Eh, 018h, 018h, 07Eh, 018h, 000h, 0FFh, 018h, 07Eh, 018h, 018h, 018h, 018h, 018h, 000h, 018h, 018h, 018h, 018h, 018h, 07Eh, 018h, 000h, 000h, 004h, 006h, 0FFh, 006h, 004h, 000h, 000h, 000h, 020h, 060h, 0FFh, 060h, 020h, 000h, 000h, 000h, 000h, 000h, 0C0h, 0C0h, 0C0h, 0FFh, 000h, 000h, 024h, 066h, 0FFh, 066h, 024h, 000h, 000h, 000h, 000h, 010h, 038h, 07Ch, 0FEh, 000h, 000h, 000h, 000h, 000h, 0FEh, 07Ch, 038h, 010h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 030h, 030h, 030h, 030h, 030h, 000h, 030h, 000h, 066h, 066h, 000h, 000h, 000h, 000h, 000h, 000h, 06Ch, 06Ch, 0FEh, 06Ch, 0FEh, 06Ch, 06Ch, 000h, 010h, 07Ch, 0D2h, 07Ch, 086h, 07Ch, 010h, 000h, 0F0h, 096h, 0FCh, 018h, 03Eh, 072h, 0DEh, 000h, 030h, 048h, 030h, 078h, 0CEh, 0CCh, 078h, 000h, 00Ch, 00Ch, 018h, 000h, 000h, 000h, 000h, 000h, 010h, 060h, 0C0h, 0C0h, 0C0h, 060h, 010h, 000h, 010h, 00Ch, 006h, 006h, 006h, 00Ch, 010h, 000h, 000h, 054h, 038h, 0FEh, 038h, 054h, 000h, 000h, 000h, 018h, 018h, 07Eh, 018h, 018h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 018h, 070h, 000h, 000h, 000h, 07Eh, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 018h, 000h, 002h, 006h, 00Ch, 018h, 030h, 060h, 0C0h, 000h, 07Ch, 0CEh, 0DEh, 0F6h, 0E6h, 0E6h, 07Ch, 000h, 018h, 038h, 078h, 018h, 018h, 018h, 03Ch, 000h, 07Ch, 0C6h, 006h, 00Ch, 030h, 060h, 0FEh, 000h, 07Ch, 0C6h, 006h, 03Ch, 006h, 0C6h, 07Ch, 000h, 00Eh, 01Eh, 036h, 066h, 0FEh, 006h, 006h, 000h, 0FEh, 0C0h, 0C0h, 0FCh, 006h, 006h, 0FCh, 000h, 07Ch, 0C6h, 0C0h, 0FCh, 0C6h, 0C6h, 07Ch, 000h, 0FEh, 006h, 00Ch, 018h, 030h, 060h, 060h, 000h, 07Ch, 0C6h, 0C6h, 07Ch, 0C6h, 0C6h, 07Ch, 000h, 07Ch, 0C6h, 0C6h, 07Eh, 006h, 0C6h, 07Ch, 000h, 000h, 030h, 000h, 000h, 000h, 030h, 000h, 000h, 000h, 030h, 000h, 000h, 000h, 030h, 020h, 000h, 000h, 01Ch, 030h, 060h, 030h, 01Ch, 000h, 000h, 000h, 000h, 07Eh, 000h, 07Eh, 000h, 000h, 000h, 000h, 070h, 018h, 00Ch, 018h, 070h, 000h, 000h, 07Ch, 0C6h, 00Ch, 018h, 030h, 000h, 030h, 000h, 07Ch, 082h, 09Ah, 0AAh, 0AAh, 09Eh, 07Ch, 000h, 07Ch, 0C6h, 0C6h, 0FEh, 0C6h, 0C6h, 0C6h, 000h, 0FCh, 066h, 066h, 07Ch, 066h, 066h, 0FCh, 000h, 07Ch, 0C6h, 0C0h, 0C0h, 0C0h, 0C6h, 07Ch, 000h, 0FCh, 066h, 066h, 066h, 066h, 066h, 0FCh, 000h, 0FEh, 062h, 068h, 078h, 068h, 062h, 0FEh, 000h, 0FEh, 062h, 068h, 078h, 068h, 060h, 0F0h, 000h, 07Ch, 0C6h, 0C6h, 0C0h, 0DEh, 0C6h, 07Ch, 000h, 0C6h, 0C6h, 0C6h, 0FEh, 0C6h, 0C6h, 0C6h, 000h, 03Ch, 018h, 018h, 018h, 018h, 018h, 03Ch, 000h, 01Eh, 00Ch, 00Ch, 00Ch, 00Ch, 0CCh, 078h, 000h, 0C6h, 0CCh, 0D8h, 0F0h, 0D8h, 0CCh, 0C6h, 000h, 0F0h, 060h, 060h, 060h, 060h, 062h, 0FEh, 000h, 0C6h, 0EEh, 0FEh, 0D6h, 0C6h, 0C6h, 0C6h, 000h, 0C6h, 0E6h, 0F6h, 0DEh, 0CEh, 0C6h, 0C6h, 000h, 07Ch, 0C6h, 0C6h, 0C6h, 0C6h, 0C6h, 07Ch, 000h, 0FCh, 066h, 066h, 07Ch, 060h, 060h, 0F0h, 000h, 07Ch, 0C6h, 0C6h, 0C6h, 0C6h, 0C6h, 07Ch, 00Ch, 0FCh, 066h, 066h, 07Ch, 066h, 066h, 0E6h, 000h, 07Ch, 0C6h, 0C0h, 07Ch, 006h, 0C6h, 07Ch, 000h, 07Eh, 05Ah, 018h, 018h, 018h, 018h, 03Ch, 000h, 0C6h, 0C6h, 0C6h, 0C6h, 0C6h, 0C6h, 07Ch, 000h, 0C6h, 0C6h, 0C6h, 0C6h, 0C6h, 06Ch, 038h, 000h, 0C6h, 0C6h, 0C6h, 0C6h, 0D6h, 0EEh, 0C6h, 000h, 0C6h, 06Ch, 038h, 038h, 038h, 06Ch, 0C6h, 000h, 066h, 066h, 066h, 03Ch, 018h, 018h, 03Ch, 000h, 0FEh, 0C6h, 00Ch, 018h, 030h, 066h, 0FEh, 000h, 01Ch, 018h, 018h, 018h, 018h, 018h, 01Ch, 000h, 0C0h, 060h, 030h, 018h, 00Ch, 006h, 002h, 000h, 070h, 030h, 030h, 030h, 030h, 030h, 070h, 000h, 000h, 000h, 010h, 038h, 06Ch, 0C6h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 0FFh, 030h, 030h, 018h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 07Ch, 006h, 07Eh, 0C6h, 07Eh, 000h, 0C0h, 0C0h, 0FCh, 0C6h, 0C6h, 0C6h, 0FCh, 000h, 000h, 000h, 07Ch, 0C6h, 0C0h, 0C6h, 07Ch, 000h, 006h, 006h, 07Eh, 0C6h, 0C6h, 0C6h, 07Eh, 000h, 000h, 000h, 07Ch, 0C6h, 0FEh, 0C0h, 07Ch, 000h, 03Ch, 066h, 060h, 0F0h, 060h, 060h, 060h, 000h, 000h, 000h, 07Eh, 0C6h, 0C6h, 07Eh, 006h, 07Ch, 0C0h, 0C0h, 0FCh, 0C6h, 0C6h, 0C6h, 0C6h, 000h, 018h, 000h, 038h, 018h, 018h, 018h, 03Ch, 000h, 000h, 00Ch, 000h, 01Ch, 00Ch, 00Ch, 0CCh, 078h, 0C0h, 0C0h, 0C6h, 0D8h, 0F0h, 0D8h, 0C6h, 000h, 038h, 018h, 018h, 018h, 018h, 018h, 03Ch, 000h, 000h, 000h, 0EEh, 0FEh, 0D6h, 0C6h, 0C6h, 000h, 000h, 000h, 0FCh, 0C6h, 0C6h, 0C6h, 0C6h, 000h, 000h, 000h, 07Ch, 0C6h, 0C6h, 0C6h, 07Ch, 000h, 000h, 000h, 0FCh, 0C6h, 0C6h, 0FCh, 0C0h, 0C0h, 000h, 000h, 07Eh, 0C6h, 0C6h, 07Eh, 006h, 006h, 000h, 000h, 0DEh, 076h, 060h, 060h, 060h, 000h, 000h, 000h, 07Ch, 0C0h, 07Ch, 006h, 07Ch, 000h, 018h, 018h, 07Eh, 018h, 018h, 018h, 01Eh, 000h, 000h, 000h, 0C6h, 0C6h, 0C6h, 0C6h, 07Eh, 000h, 000h, 000h, 0C6h, 0C6h, 0C6h, 06Ch, 038h, 000h, 000h, 000h, 0C6h, 0C6h, 0D6h, 0FEh, 0C6h, 000h, 000h, 000h, 0C6h, 06Ch, 038h, 06Ch, 0C6h, 000h, 000h, 000h, 0C6h, 0C6h, 0C6h, 07Eh, 006h, 07Ch, 000h, 000h, 0FEh, 00Ch, 018h, 060h, 0FEh, 000h, 00Eh, 018h, 018h, 070h, 018h, 018h, 00Eh, 000h, 018h, 018h, 018h, 000h, 018h, 018h, 018h, 000h, 0E0h, 030h, 030h, 01Ch, 030h, 030h, 0E0h, 000h, 000h, 000h, 070h, 09Ah, 00Eh, 000h, 000h, 000h, 000h, 000h, 018h, 03Ch, 066h, 0FFh, 000h, 000h
  demostr:
           DEFB "flockaroo presents --=#[ ZX-Mountains ]#=-- "
           DEFB " an infinite mountain scape ",127,"2024 "
           DEFB "...found my old ZX-Spectrum in some forgotten closet... got inspired... and carried away... "
           DEFB "cold jump into assembly waters, after long time only shader programming. "
           DEFB "...for a change. "
           DEFB "oh, oh, so sloooow "
           DEFB "...now some garbage: "
  ; use dos font or spectrum ROM-font
  #define MYFNT 3C00h
  ;#define MYFNT DosFont8

end_of_data:

     ; FCx - get from mem
     ld HL,FCx
     ld C,(HL)
     inc HL
     ld B,(HL)
     push BC

;use ordered halftone (bayer) or my own bitinv noise
#define USE_BAYER
#ifndef USE_BAYER
  ;DIM biX7 as integer=7*binv8(FCx&255)
     pop HL ; get BC from above (FCx)
     ld C,L
     ld B,0
     ld HL,binv8
     ADD HL,BC
     ;ld L,(HL)
     ld E,(HL)
     ld H,7
     push BC
     CALL mul8_HL_H_E
     pop BC
     push HL
     pop BC
     ld HL,biX7
     ld (HL),C
     inc HL
     ld (HL),B
#endif

; uncomment to step from nearest to farest mountsins (default far to near)
;#define Hi_DOWN_LOOP
     #ifndef Hi_DOWN_LOOP
      ld HL,lastmin ; optim: init last actual mountain
      ld (HL),0     ; optim: init last actual mountain
     #else
      push DE
      ld HL,Hnum
      ld D,(HL)
      dec D
      ld HL,lastmin ; optim: init last actual mountain
      ld (HL),D     ; optim: init last actual mountain
      pop DE
     #endif

;  screen addr = 0x401F (rightmost byte on top)
   ld HL,401Fh
;  FOR FCy=0 to 192
   ld C,0
   forFCy:
     ld A,C
     cp 192
     jp z,forFCyEnd

     push BC
     push HL ; push addr
#ifndef USE_BAYER
     ;DIM pat as ubyte=int(73*binv8(FCy)+biX7) MOD 255
      ld HL,binv8
      ld B,0
      ADD HL,BC
      ;ld L,(HL)
      ld E,(HL)
      ;ld H,73
      ld H,3
      push BC
      CALL mul8_HL_H_E
      pop BC
      push HL
       ld HL,biX7
       ld C,(HL)
       inc HL
       ld B,(HL)
      pop HL
      ADD HL,BC
      ld D,255
      push BC
      CALL mod8_HL_HL_D
      pop BC
      ld E,L  ; E=pat
#else
      ld HL,FCx
      ld A,(HL)
      ld E,A
      and 7
      SLA A
      SLA A
      SLA A
      ld HL,bayer
      push DE
       ld D,0
       ld E,A
       add HL,DE
      pop DE
      push BC
       ld B,0
       ld A,C
       and 7
       ld C,A
       ADD HL,BC
      pop BC
      ld E,(HL)
      SLA E
      SLA E
#endif
     pop HL ; pop addr
     pop BC

     push DE ; push pat
     push BC ; push bright,FCy
     push HL ; push addr
     ld A,235
     ld B,C
     SLA B
     SLA B
     SUB B
     ld B,A
;    FOR i=0 to Hnum-1  (...or FOR i=Hnum-1 to 0)
     ld HL,lastmin ; optim: load last actual mountain
     ld D,(HL)     ; optim: load last actual mountain
     for_i:
      ;if(FCy>H(i))
       push DE
       push BC
       ld A,C
       ld HL,Hi
       ld E,D    ; push D
        ld D,0
        add HL,DE
       ld D,E    ; pop D
       ld E,(HL) ; E now holds H(i) (where i=D)
       cp E
       jp c,label1 ; cflag set when FCy<Hi
        ;B=127-(i+1)*(dC>>1)+(FCy-H(i))*2*Hnum/(i+1)
     #ifndef Hi_DOWN_LOOP
         ld HL,lastmin ; optim: store last actual mountain
         ld (HL),D     ; optim: store last actual mountain
     #endif
         push DE
          ld E,D
          inc E
          ld HL,dC
          ld H,(HL)
          SRL H
          CALL mul8_HL_H_E  ; HL=(i+1)*(dC>>1)
         pop DE
         push HL

          ld A,C
          SUB E              ; A=FCy-Hi
          ld HL,Hnum
          ld E,(HL)
          ld H,A
          ;push AF
           ;SLA E              ; E=Hnum*2
           ld A,E
           SRL E
           add A,E             ; Hnum*1.5
           ld E,A
          ;pop AF
          CALL mul8_HL_H_E   ; HL=(Fc-Hi)*2*Hnum
          push DE
           inc D
	   CALL div8_HL_HL_D ; HL=(Fc-Hi)*2*Hnum/(i+1)
          pop DE
          ld A,L
          ADD A,100          ; A=127+(Fc-Hi)*2*Hnum/(i+1)
         pop BC              ; BC=(i+1)*(dC>>1)
         sub C
         ld B,A              ; B=127-(i+1)*(dC>>1)+(FCy-H(i))*2*Hnum/(i+1)
     #ifdef Hi_DOWN_LOOP
         ld A,B   ; preserve B(=brightness)
         pop BC
         ld B,A   ; preserve B(=brightness)
         pop DE
         jp breakHi
     #endif

       label1:
       ld A,B   ; preserve B(=brightness)
       pop BC
       ld B,A   ; preserve B(=brightness)
       pop DE
     #ifndef Hi_DOWN_LOOP
       inc D
       ld HL,Hnum
       ld A,(HL)
       cp D
     jp nz,for_i
     #else
       dec D
       ld A,255
       cp D
     jp nz,for_i
     breakHi:
     #endif

     pop HL ; HL=addr
     ld A,B ; preserve B=bright
     pop BC ; pop FCy (C)
     ld B,A ; preserve B=bright
     pop DE ; pop pat (E)

; add text banner on bottom
#if 1
    push BC

    push DE
    push HL
    ld HL,bsin6
    ld DE,(FCx)
    ld A,E
    SRL A
    SRL A
    AND 63
    ld E,A
    ld D,0
    ld A,C
    add HL,DE
    ld E,(HL)
    SRL E
    SRL E
    SRL E
    SRL E
    add A,E
    ld C,A
    pop HL
    pop DE

    ld A,159
    CP C
    jp nc,notext:
    ld A,175
    CP C
    jp c,notext:
    SRL B
    ;SLA B
     ; add scrolltext to B
     push HL
     push DE
     push BC
      ;D=FCx/2&7
      ld A,(FCx)
      SRL A
      AND 7
      ld D,A
      PUSH DE
       ;E=str(FCx/16)
       ld DE,(FCx)

       SRL D
       jp nc,Xshift1_jp1
       SRL E
       SET 7,E
       jp Xshift1_jp2
       Xshift1_jp1:
       SRL E
       Xshift1_jp2:

       SRL D
       jp nc,Xshift2_jp1
       SRL E
       SET 7,E
       jp Xshift2_jp2
       Xshift2_jp1:
       SRL E
       Xshift2_jp2:

       SRL D
       jp nc,Xshift3_jp1
       SRL E
       SET 7,E
       jp Xshift3_jp2
       Xshift3_jp1:
       SRL E
       Xshift3_jp2:

       SRL D
       jp nc,Xshift4_jp1
       SRL E
       SET 7,E
       jp Xshift4_jp2
       Xshift4_jp1:
       SRL E
       Xshift4_jp2:

       ld HL,demostr
       ADD HL,DE
       ld A,(HL)     ; A=char
       ;ld HL,Font8+D*8+C/2

       ; 16 bit SLA
       ld D,0
       SLA A
       jp nc,shift1_jp1
       SLA D
       SET 0,D
       jp shift1_jp2
       shift1_jp1:
       SLA D
       shift1_jp2:

       SLA A
       jp nc,shift2_jp1
       SLA D
       SET 0,D
       jp shift2_jp2
       shift2_jp1:
       SLA D
       shift2_jp2:

       SLA A
       jp nc,shift3_jp1
       SLA D
       SET 0,D
       jp shift3_jp2
       shift3_jp1:
       SLA D
       shift3_jp2:

       ld E,A         ; DE=char*8
       ;ld HL,Font8
       ld HL,MYFNT
       ADD HL,DE

       LD A,C
       SRL A
       AND 7
       ld E,A       ; E=(FCy/2)%8
       ld D,0
       ADD HL,DE
      POP DE
      push BC
       ld B,(HL)
       ld A,D        ; A=(FCx/2)%8
       fontjmp1:
       cp 0
       jp z,fontjmp2
       SLA B
       dec A
       jp fontjmp1
       fontjmp2:
       ld A,B
      pop BC
      BIT 7,A
      jp z,nochar
       ld A,167
       ADD A,B
       ld B,A
       ;ld B,255  ; fully white text - no halftone
      nochar:
     LD A,B
     pop BC
     LD B,A
     pop DE
     pop HL
    notext:
    ld A,B
    pop BC
    ld B,A
#endif

     ;if pat>br THEN POKE addr, 255 else POKE addr, 0
     ;ld (HL),255
     SET 0,(HL)
     ld A,B
     cp E
     jp c,label2
        ;ld (HL),0
        RES 0,(HL)
     label2:
     ; addr=addr+256
     inc H

     ;if (FCy &  7 =  7) THEN addr=addr-2016
     ld A,C
     and 7
     cp 7
       jp nz,label3
       ;SUB HL,2016
       push BC
       ld BC,0F820h
       ADD HL,BC
       pop BC
     label3:
     ld A,C

     ;if (FCy & 63 = 63) THEN addr=addr+1792
     and 63
     cp 63
       jp nz,label4
       push BC
       ld BC,1792
       ADD HL,BC
       pop BC
     label4:

     inc C
   jp forFCy
   forFCyEnd:
   END ASM
 end function

function fastcall scrollX(x as ubyte) as ubyte
REM arg x ignored for now, just scroll 1 pixel
   ASM
   LD HL,4000h
   SLA (HL)
   inc HL
loop0:
   SLA (HL)
   JP nc,jmp1
   DEC HL
   SET 0,(HL)
   INC HL
jmp1:
   inc HL
   LD A,H
   CP 58h
   JP nz,loop0
   END ASM
end function


DIM FCx as uinteger=0
WHILE 1

  drawRightColAsm(FCx)
  scrollX(1)
  FCx=FCx+1

END WHILE

 

ssd crash: how i almost lost my home-drive but got almost all data back

Details
Geschrieben von: flockaroo
Kategorie: Uncategorised
Veröffentlicht: 13. Juni 2023
Zugriffe: 1182

ssd crash - or, how i almost lost my whole ext4-home-drive but got almost all data back

...one fine day, i had a really bad day...

...so here's the report from my odyssey:

...what happened (most likely) was, that my ssd got too little power for a while and some data got (permanently) lost.

i transitionally (and stupidly) used an old power supply in an old case, that was most likely under-dimensioned, and my GeForce-3070 drew too much power - leaving the disks slightly under-supplied (at least that's my suspicion on what happened). it worked quite well for a while, but one day during a more intense graphics session the screen suddenly froze and the system would not be able to mount my home disk on reboot. no way to mount the drive anymore, there was a lot of input/output errors... i thought i was out of luck...

what i found on internet/forums was, that if there's input/output-errors, you can assume that the disk is dead or dying, no way to restore data whatsoever...

i didn't dare to fsck because i didn't want to risk any writing to the damaged disk (not even sure if fsck wouldn't have worked properly at all on input/output errors)

...so, here's what i did:

first i tried to "dd" the whole disk to a file, but every time an input /output error occured, dd would of course stop.

but the i/o errors were distinctly bound to certain blocks, so i just wrote a small script that would just report the bad blocks into a log file and with every new start continue on the next potentially undamaged block - you cannot use this script just like this, it's more of explanatory use, because a lot is hardcoded here e.g. the drive '/dev/sdd'... - so i put this script here without warranty -  just use/adapt it at your own risk, and only if you know what you are doing!!

#!/bin/sh

BAKFILE="bak_sdd_all.raw"
BSIZE=512

ALLCNT=0
if test -e $BAKFILE; then
  ALLCNT=$(du -b $BAKFILE)
  ALLCNT=${ALLCNT%%$BAKFILE}
  #echo "allcnt= $ALLCNT"
  ALLCNT=$[ALLCNT/BSIZE+1]
  echo "proceed at: $ALLCNT"
fi

ALLBLOCKS=3907029168

NUMBLOCKS=$[ALLBLOCKS-ALLCNT]
echo "          ...try copy $NUMBLOCKS blocks"

if [ "$NUMBLOCKS" -le "0" ]; then exit 1; fi

set +e

dd if=/dev/sdd of=$BAKFILE bs=$BSIZE skip=$ALLCNT seek=$ALLCNT count=$NUMBLOCKS > make_bak_last.out 2>&1

set -e

LASTCNT=$(grep -o '^.*records in' make_bak_last.out)

LASTCNT=${LASTCNT%%+*}
ALLCNT=$[ALLCNT+LASTCNT]


echo "$ALLCNT - $LASTCNT" | tee -a "$BAKFILE.log"

...and that script i then executed in an endless loop until all data was copied:

#!/bin/sh
while true; do 
   if ! ./make_bak_sdd ; then
      exit 1;
   fi
done

 

(edit: from a user comment, i got the hint, that the option "noerror" of dd can also copy all data without interrupting - ...of course i would not get a log file then)

the copying took quite a while, because every bad block would block the whole process for several seconds, and even some of the intact blocks seemed to copy slower than others.

first i just browsed through the raw data to find some source files i lost by just string-searching the whole 2TB for certain strings, i knew would only occur in my files. that's where i already got lucky and got back a few files i would have deeply missed instead. but that method is only useful for readable files, where you actually have a distinct idea of parts of the content.

as stated before, in the .log file of the above script i already got all the dead blocks listed, because every time dd interrupted, a line was added to the log.

this way i was able to make a small pyhton script, that showed me all the bad blocks (...or at least regions with bad blocks). and furthermore i extended the program to even be able to hex-view directly by pointing with the mouse to a region and also added a nifty (kind of performant) string search feature. ...might be handy for others so i also add the source here, too. i also give this here to the public without any warranty. use at your own risk, and only use it if you know what you're doing.

the script uses tkinter as a gui, and also a lot here is hardcoded. e.g it assumes a 2TB disk (deviceblocks=3907029168 (each 512bytes)).

it takes the log file (with the bad blocks) as an argument and reads the actual data (for displaying hex-data info) from the accordingly named raw-data file (without the ".log" suffix in the end - also here simply hardcoded by stripping the suffix)

#!/usr/bin/python3
import os, sys, math, mmap, tkinter

window = tkinter.Tk()

deviceblocks=3907029168;
blockspp=4096;
startblock=0
psiz=2
#W=1792
#H=1066
#W=1024
#H=1024
W=1384
H=1384

if len(sys.argv)<2 : print("usage: bla file [blockspp [startblock [psiz [W [H]]]]]"); exit(1);
fname=sys.argv[1]
if len(sys.argv)>2 : blockspp=int(sys.argv[2],0)
if len(sys.argv)>3 : startblock=int(sys.argv[3],0)
if len(sys.argv)>4 : psiz=int(sys.argv[4],0)
if len(sys.argv)>5 : W=int(sys.argv[5],0)
if len(sys.argv)>6 : H=int(sys.argv[6],0)

Nall=int(W/psiz)*int(H/psiz)
Ndevice=int((deviceblocks+blockspp-1)/blockspp)

#window.geometry(""+str(W)+"x"+str(H))
window.geometry("%dx%d"%(W,H))
canv = tkinter.Canvas(window, width=W, height=H)

ring=bytearray(256)
ringi=0

actblock=startblock
acterrs=0
actidx=0
errcnt=0
errs=[]
with open(fname, mode="r") as file:
    for line in file:
        vals=line.rstrip().split(" - ")
        errblock=int(vals[0])
        blocksbefore=int(vals[1])
        while errblock>=actblock+blockspp:
           errs.append(acterrs)
           errcnt+=acterrs
           if acterrs!=0 : print(acterrs)
           acterrs=0
           actblock+=blockspp
        if len(errs)>=Nall: break;
        acterrs+=1

idx=0
for y in range(0,H,psiz):
   for x in range(0,W,psiz):
      r=int(x/psiz);
      g=int(y/psiz);
      b=0;
      r=255;
      g=128;
      b=0;
      if idx<len(errs):
         v01=0
         if errs[idx]>0 :
            v01=max(0.,min(1.,errs[idx]/blockspp))
            v01=math.pow(v01,.5)
            r=int(v01*255.999)
            g=int((1.-v01)*255.999)
            b=0
         else :
            r=g=b=255
      if idx>Ndevice : [r,g,b]=[0,0,255]
      idx+=1
      col='#'+('%02x'%r)+('%02x'%g)+('%02x'%b)
      canv.create_rectangle(x, y, x+psiz, y+psiz, width=0, fill=col)

numbytesFull=Nall*blockspp*512
numbytes=(actblock-startblock+1)*512
txt=""
txt+='%d / (%d) bytes'%(numbytes,numbytesFull)
txt+="\n\n"
txt+="%.3f MB"%(numbytes/1024/1024)
txt+="\n\n"
txt+="%.3f GB"%(numbytes/1024/1024/1024)
txt+="\n\n"
txt+='%.3f MB = %.6f %% damaged'%(errcnt*512/1024/1024,errcnt/(actblock-startblock+1)*100.0)
sumtext=canv.create_text(W/2, H/2, text=txt)
hexview=None
hexoffs=0
hexhex=0

def entryCb(v):
    global hexview, hexoffs
    hexoffs=int(v.get())
    pos=canv.coords(hexview)
    updateHexView(pos[0],pos[1],hexoffs);

entryVar = tkinter.StringVar()
entryVar.trace("w", lambda name, index, mode, entryVar=entryVar: entryCb(entryVar))
searchEntryVar = tkinter.StringVar()

def myread(fname, offs, size) :
    with open(fname, mode="rb") as file:
       file.seek(offs)
       return file.read(size)

def readableCh(ch) :
    if ch>=32 and ch<=126: return ch
    return ord('.')

def bytes2hex(data,xnum,dohex) :
    txt=""
    line=""
    line2=""
    for i in range(len(data)):
       line+="%02x "%data[i]
       line2+="%c"%readableCh(data[i])
       if (i%xnum)==xnum-1 :
          ll=line2
          if dohex==1: ll=line+" "+line2
          txt+=ll+"\n"
          line=""
          line2=""
    return txt

def updateHexView(x,y,offs):
    global sumtext, hexview, hexhex
    lnum=48
    xnum=32
    if hexhex==0: xnum=128
    cdata=myread(fname.replace(".log",""),offs,xnum*lnum);
    txt=("offs=%d\n"%offs)+bytes2hex(cdata,xnum,hexhex);
    print("offs=%d"%offs)
    if hexview != None : canv.delete(hexview)
    if sumtext != None :
       canv.delete(sumtext)
       sumtext=None
    #hexview=canv.create_text(x,y,text=txt,font='TkFixedFont')
    hexview=canv.create_text(x,y,text=txt,font=('Mono',6))
    bbox=canv.bbox(hexview);
    if bbox[0]<0 : canv.move(hexview,-bbox[0],0)
    if bbox[2]>W : canv.move(hexview,-bbox[2]+W,0)
    if bbox[1]<0 : canv.move(hexview,0,-bbox[1])
    if bbox[3]>H : canv.move(hexview,0,-bbox[3]+H)
    canv.pack()

def updateHexView0():
    global hexview, hexoffs
    pos=canv.coords(hexview)
    updateHexView(pos[0],pos[1],hexoffs);

def lclick(event):
    global hexview, hexoffs
    x, y = event.x, event.y
    hexoffs=(int(y/psiz)*int(W/psiz)+int(x/psiz))*blockspp*512
    updateHexView(x,y,hexoffs)

def prevPage(e):
    global hexview, hexoffs, hexhex
    lnum=48
    xnum=32
    if hexhex==0: xnum=128
    hexoffs-=lnum*xnum
    updateHexView0()

def nextPage(e):
    global hexview, hexoffs, hexhex
    lnum=48
    xnum=32
    if hexhex==0: xnum=128
    hexoffs+=lnum*xnum
    updateHexView0()

def prevLine(e):
    global hexview, hexoffs, hexhex
    lnum=48
    xnum=32
    if hexhex==0: xnum=128
    hexoffs-=xnum
    updateHexView0()

def nextLine(e):
    global hexview, hexoffs, hexhex
    lnum=48
    xnum=32
    if hexhex==0: xnum=128
    hexoffs+=xnum
    updateHexView0()

def checkRing(b1):
    global ring, ringi
    lr=len(ring)
    lb=len(b1)
    ri=(ringi+lr+lr-lb)%lr
    for i in range(lb) :
       if b1[i]!=ring[ri] : return 0
       ri=(ri+1)%lb
    return 1

def searchStr():
    ### FIXME: optimize me
    global hexoffs, fname, ring, ringi
    with open(fname.replace(".log",""), mode="rb") as file:
       file.seek(hexoffs)
       rpos=hexoffs
       lr=len(ring)
       b1=bytes(searchEntryVar.get(),'UTF-8')
       while 1:
          ch = file.read(1)
          if not ch: print("not found"); break;
          ring[ringi] = ch[0];
          ringi=(ringi+1)%lr
          if(checkRing(b1)):
             print("found at pos "+str(rpos))
             hexoffs=rpos
             updateHexView0()
             break;
          rpos+=1
          if((rpos-hexoffs)%10000000==0) : print("search offs = "+str(rpos-hexoffs))


def searchStrMM():
    global hexoffs, fname, ring, ringi
    offs=hexoffs
    bsize=1024*1024*128
    b1=bytes(searchEntryVar.get(),'UTF-8')
    ## do e really need os. here?
    myfname=fname.replace(".log","")
    fsize = os.path.getsize(myfname)
    with open(myfname, mode="rb") as file:
       while 1:
          offs1=offs%mmap.ALLOCATIONGRANULARITY
          offs0=offs-offs1
          if offs>=fsize : break
          if offs0+bsize>fsize : bsize=fsize-offs0
          s = mmap.mmap(file.fileno(), length=bsize, access=mmap.ACCESS_READ, offset=offs0)
          res = s.find(b1,offs1)
          if res != -1:
             print("found at pos "+str(offs0+res))
             entryVar.set(offs0+res)
             #hexoffs=offs0+res
             #updateHexView0()
             return
          else:
             offs+=bsize-len(b1)+1
             print("search off=%d (%.2fG)"%(offs,offs/(1024*1024*1024)))
       print("not found")
       return

def openOffsetPopup(e):
    global entryVar
    top=tkinter.Toplevel(window)
    top.geometry("320x200")
    top.title("Offset Control")
    #tkinter.Label(top, text= "Enter Offset!", font=('Mistral 12 bold')).place(x=0,y=40)
    tkinter.Label(top, text= "Enter Offset:").place(x=10,y=10)
    entryVar.set(str(hexoffs))
    tkinter.Entry(top,textvariable=entryVar).place(x=20,y=30)
    tkinter.Entry(top,textvariable=searchEntryVar).place(x=20,y=50)
    tkinter.Button(top, text="search", command=searchStrMM).place(x=20,y=70)

def toggleHex(e):
    global hexhex
    if hexhex==0 : hexhex=1
    else : hexhex=0
    updateHexView0()

#window.bind('<Motion>', lclick)
window.bind('<B1-Motion>', lclick)
window.bind('<Button-1>', lclick)
window.bind('<Prior>', prevPage)
window.bind('<Next>', nextPage)
window.bind('<Up>', prevLine)
window.bind('<Down>', nextLine)
window.bind('o', openOffsetPopup)
window.bind('h', toggleHex)

canv.pack()
window.mainloop()

 

here is the final view of my log file in the python script - each pixel (or actually 2x2 pixels) holds 8192 blocks (can be given as argument) of 512 bytes each. the green/dark pixels mark damaged blocks (bright green to red for little to many damaged blocks). the blue region in the end is just the region beyond the actual ssd-capacity (as stated - here hardcoded). (also check the window.bind(...) commands in the end of the script for key-functions)

python-view-tool

and another one with some hexing-action by just clicking anywhere on the data-region (...here obviously some excerpt from the face-section of a wavefront/obj file):

hexhex...

happy end (hopefully)

but hey, now for the best part... it turned out, in the end the whole raw-data browsing by hand was actually more or less just for the fun of it...

the big raw-data file i got in the end i simply dd'ed to a new equivalent ssd-drive and it mounted like charm (even without fsck) - of course some file content or maybe even whole files/directories might still be lost, but so far i didn't notice anything missing :-) ...didn't try to do a fsck on the new disk so far - for now i just mount it purely readonly and copy back old stuff to my new home on demand when i need it.

conclusion:

...don't throw away your disk just because the system doesn't mount it anymore!! make an image to a file/or even another disk, by just ignoring bad blocks. it might work - it did for me!

...and don't use too weak power supplies it might kill your ssd-drives (...but that's just my suspicion here)

as a matter of fact i'm quite disappointed, that the file system (here ext4) would just go bonkers and not let me see any files at all. i could have lived with it being slow, when stumbling over bad blocks, but just to give input/output errors and bailing out and not mounting (even when all needed information is obviously still on the disk) is not nice - ...son i'm disappoint :-(

 

  • Home