dcf77_pin=6 led_pin=4 min_ambient_light=25 last_valid_rise=0 valid_rise_min=990000 valid_rise_max=1010000 valid_timeout=5000000 valid_newmin_min=1990000 valid_newmin_max=2100000 valid_0_min=100000 valid_0_max=140000 valid_1_min=200000 valid_1_max=250000 dcfdata="" valid_times=0 total_times=0 bcd={} bcd[1]=1 bcd[2]=2 bcd[3]=4 bcd[4]=8 bcd[5]=10 bcd[6]=20 bcd[7]=40 bcd[8]=80 dow={} dow[0]="Invalid" dow[1]="Mon" dow[2]="Tue" dow[3]="Wed" dow[4]="Thu" dow[5]="Fri" dow[6]="Sat" dow[7]="Sun" mon_days={} mon_days[1]=31 mon_days[2]=28 mon_days[3]=31 mon_days[4]=30 mon_days[5]=31 mon_days[6]=30 mon_days[7]=31 mon_days[8]=31 mon_days[9]=30 mon_days[10]=31 mon_days[11]=30 mon_days[12]=31 function bcd2dec(data) local value=0 for count=1,string.len(data),1 do if string.sub(data,count,count)=="1" and bcd[count]~=nil then value=value+bcd[count] end end return value end function check_parity(data) local onecount=0 for count=1,string.len(data),1 do if string.sub(data,count,count)=="1" then onecount=onecount+1 end end if onecount%2==0 then return true end return false end gps_sec=0 gps_valid=false gps_part1="" gps_part2="" gps_part_checksum=0 hex={} hex[0]="0" hex[1]="1" hex[2]="2" hex[3]="3" hex[4]="4" hex[5]="5" hex[6]="6" hex[7]="7" hex[8]="8" hex[9]="9" hex[10]="A" hex[11]="B" hex[12]="C" hex[13]="D" hex[14]="E" hex[15]="F" function send_gpsstring() local gps_data local gps_checksum=gps_part_checksum local part1len=string.len(gps_part1) if gps_sec<10 then gps_data=gps_part1.."0"..gps_sec..gps_part2 else gps_data=gps_part1..gps_sec..gps_part2 end gps_checksum=bit.bxor(gps_checksum,string.byte(string.sub(gps_data,part1len+1,part1len+1))) gps_checksum=bit.bxor(gps_checksum,string.byte(string.sub(gps_data,part1len+2,part1len+2))) local digit1=bit.rshift(gps_checksum,4) local digit2=bit.band(gps_checksum,15) print("$"..gps_data.."*"..hex[digit1]..hex[digit2].."\r") end function parse_data(data) total_times=total_times+1 --print("-------------------------------------------------------------") --print(data) --print("Resrv: ",string.sub(data,1,15)) --print("Info: ",string.sub(data,16,21)) --print("Min: ",string.sub(data,22,29),bcd2dec(string.sub(data,22,28)),check_parity(string.sub(data,22,29))) --print("Hour: ",string.sub(data,30,36).." ",bcd2dec(string.sub(data,30,35)),check_parity(string.sub(data,30,36))) --print("Day: ",string.sub(data,37,42).." ",bcd2dec(string.sub(data,37,42))) --print("DOW: ",string.sub(data,43,45).." ",bcd2dec(string.sub(data,43,45))) --print("Month: ",string.sub(data,46,50).." ",bcd2dec(string.sub(data,46,50))) --print("Year: ",string.sub(data,51,59),bcd2dec(string.sub(data,51,59)),check_parity(string.sub(data,37,59))) --print("Rest: ",string.sub(data,60)) --if string.len(data)==59 then -- print("Time/date : "..bcd2dec(string.sub(data,30,35))..":"..bcd2dec(string.sub(data,22,28)).." "..dow[bcd2dec(string.sub(data,43,45))].." 20"..bcd2dec(string.sub(data,51,59)).."-"..bcd2dec(string.sub(data,46,50)).."-"..bcd2dec(string.sub(data,37,42))) --end gps_valid=false local min local hour local day local mon local year if data==nil then --print("No data received") return end if string.len(data)~=59 then --print("Data length invalid") return end --print("Data length valid") if string.sub(data,18,18)==string.sub(data,19,19) then --print("Timezone data is invalid") return end --print("Timezone data is valid") if string.sub(data,21,21)=="0" then --print("Start time bit is invalid") return end --print("Start time bit is valid") if not check_parity(string.sub(data,22,29)) then --print("Minute parity invalid") return end --print("Minute parity valid") min=bcd2dec(string.sub(data,22,28)) if min>59 then --print("Minute value invalid") return end --print("Minute value valid") if not check_parity(string.sub(data,30,36)) then --print("Hour parity invalid") return end --print("Hour parity valid") hour=bcd2dec(string.sub(data,30,35)) if hour>23 then --print("Hour valid invalid") return end --print("Hour valid valid") if not check_parity(string.sub(data,37,59)) then --print("Date parity invalid") return end --print("Date parity valid") day=bcd2dec(string.sub(data,37,42)) if day<1 or day>31 then --print("Day value invalid") return end --print("Day valud valid") mon=bcd2dec(string.sub(data,46,50)) if mon<1 or mon>12 then --print("Month value invalid") return end --print("Month value valid") year=bcd2dec(string.sub(data,51,59)) if year<22 or year>30 then --print("Year value invalid") return end --print("Year value valid") valid_times=valid_times+1 --print("Total "..valid_times.." valid times and "..total_times-valid_times.." invalid times") --if string.sub(data,18,18)==1 then --print("Subtracting 1 hour for CET timezone") --hour=hour-1 --else --print("Subtracting 2 hours for CEST timezone") --hour=hour-2 --end hour=hour-1 if hour<0 then hour=hour+24 day=day-1 if day<1 then mon=mon-1 if mon<1 then mon=12 year=year-1 end if mon==2 and year%4==0 then day=day+1 end day=mon_days[mon] end end gps_part1=string.format("GPZDA,%02d%02d",hour,min) gps_part2=string.format(".000,%02d,%02d,20%02d,,",day,mon,year) local gps_data=gps_part1..gps_part2 gps_part_checksum=0 for count=1,string.len(gps_data) do gps_part_checksum=bit.bxor(gps_part_checksum,string.byte(string.sub(gps_data,count,count))) end gps_sec=0 gps_valid=true send_gpsstring() end function irq_handler(level,when,count) if count>10 then --print("Waiting for stable signal, changing to polling") start_poll() return end if whenvalid_newmin_min and deltavalid_rise_min and deltamin_ambient_light then gpio.write(led_pin,gpio.LOW) end else gps_valid=false gpio.write(led_pin,gpio.HIGH) end end return end if delta>valid_timeout then --print("Valid timeout") last_valid_rise=0 return end end if level==0 then --print("Pulse length: "..delta) if delta>valid_0_min and deltavalid_1_min and delta59 then dcfdata=string.sub(dcfdata,2) end end end function irq_dummy(level,when,count) --print("Dummy IRQ handler") return end poll_prev_value=0 poll_value_count={} poll_value_count[0]=0 poll_value_count[1]=0 poll_clean=0 function poll_handler() local value value=gpio.read(dcf77_pin) if value==nil then poll_timer:start() end if value==1 and poll_prev_value==0 then --print(poll_value_count[0],poll_value_count[1]) if poll_value_count[0]>70 and poll_value_count[0]<100 and poll_value_count[1]>6 and poll_value_count[1]<30 then poll_clean=poll_clean+1 --print(poll_clean.." clean pulses") if poll_clean>10 then poll_clean=0 --print("Clean signal, swithcing to IRQ handling") start_irq() return end else poll_clean=0 end poll_value_count[0]=0 poll_value_count[1]=0 end poll_prev_value=value poll_value_count[value]=poll_value_count[value]+1 poll_timer:start() end poll_timer=tmr.create() poll_timer:register(10, tmr.ALARM_SEMI,poll_handler) function start_poll() gpio.write(led_pin,gpio.HIGH) gpio.trig(dcf77_pin,"none",irq_dummy) gpio.mode(dcf77_pin,gpio.INPUT) poll_timer:start() end function start_irq() gpio.mode(led_pin,gpio.OUTPUT) gpio.write(led_pin,gpio.HIGH) gps_valid=false gpio.trig(dcf77_pin,"both",irq_handler) gpio.mode(dcf77_pin,gpio.INT) end function start_dcf77() start_irq() end function stop_dcf77() gpio.mode(dcf77_pin,gpio.INPUT) poll_timer:stop() gpio.write(led_pin,gpio.HIGH) end